All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.heroku.api.parser.Json Maven / Gradle / Ivy

There is a newer version: 0.46
Show newest version
package com.heroku.api.parser;


import com.heroku.api.exception.ParseException;
import com.heroku.api.http.HttpUtil;
import com.heroku.api.request.Request;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Iterator;
import java.util.ServiceLoader;

public class Json {

    static class Holder {
        static Parser parser;

        static {
            ServiceLoader loader = ServiceLoader.load(Parser.class, Parser.class.getClassLoader());
            Iterator iterator = loader.iterator();
            if (iterator.hasNext()) {
                parser = iterator.next();
            } else {
                throw new IllegalStateException("Unable to load a JSONProvider, please make sure you have a com.heroku.api.json.JSONParser implementation" +
                        "on your classpath that can be discovered and loaded via java.util.ServiceLoader");
            }
        }
    }


    /**
     * Calls Parser.parse() using the generic type T for Request given Request is the interface for the
     * classType parameter. If it can't find an appropriate type, it errors out with a ParseException.
     * 

* The following code sample illustrates typical usage in the context of a request to Heroku's API. * The byte array is provided from a connection.execute(request) call, which is a JSON response from * the server. getClass() provides the classType, which in this case extends Request. The return * value from the parse method will be App. * * public class SampleRequest implements Request { * ... * public App getResponse(byte[] data, int status) { * return Json.parse(data, getClass()); * } * } * * * @param data JSON byte array to be parsed * @param classType The Request implementation class type. This is typically given the calling class as * an argument. * @return T */ public static T parse(byte[] data, Class> classType) { Type[] types = doResolveTypeArguments(classType, classType, Request.class); if (types == null || types.length == 0) { throw new ParseException("Request was not found for " + classType); } Type type = types[0]; try { return Holder.parser.parse(data, type); } catch (RuntimeException e) { String json = HttpUtil.getUTF8String(data); throw new ParseException("Failed to parse JSON:" + json, e); } } /* * slightly modded version of spring GenericTypeResolver methods */ private static Type[] doResolveTypeArguments(Class ownerClass, Class classToIntrospect, Class genericIfc) { while (classToIntrospect != null) { if (genericIfc.isInterface()) { Type[] ifcs = classToIntrospect.getGenericInterfaces(); for (Type ifc : ifcs) { Type[] result = doResolveTypeArguments(ownerClass, ifc, genericIfc); if (result != null) { return result; } } } else { Type[] result = doResolveTypeArguments(ownerClass, classToIntrospect.getGenericSuperclass(), genericIfc); if (result != null) { return result; } } classToIntrospect = classToIntrospect.getSuperclass(); } return null; } private static Type[] doResolveTypeArguments(Class ownerClass, Type ifc, Class genericIfc) { if (ifc instanceof ParameterizedType) { ParameterizedType paramIfc = (ParameterizedType) ifc; Type rawType = paramIfc.getRawType(); if (genericIfc.equals(rawType)) { return paramIfc.getActualTypeArguments(); } else if (genericIfc.isAssignableFrom((Class) rawType)) { return doResolveTypeArguments(ownerClass, (Class) rawType, genericIfc); } } else if (ifc != null && genericIfc.isAssignableFrom((Class) ifc)) { return doResolveTypeArguments(ownerClass, (Class) ifc, genericIfc); } return null; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy