adamdubiel / jason

Elastic gson fork.
Other
0 stars 0 forks source link

interfaces and autobeans. #3

Open jnorthrup opened 10 years ago

jnorthrup commented 10 years ago

I have something that you may want to pick up and run with.

im using gwt autobeans and had to figure out a way to make gson work around incompatible proxies on the server side. what works is to use groovy to be the enclosing classloader during TypeAdapter registration and for groovy to copmile the adapter class and register it. the generation code can be cleaned up and some references to my gson singletions exist here. i think the generated fromJson method is now superfluous as well. this is the only groovy in my project, fwiw, using pure java syntax, so cleaner solutions exist with bytecode engineering, but this one was an easy sample to plug in.

cheers.

import com.google.gson.GsonBuilder; import com.google.gson.InstanceCreator; import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory; import groovy.lang.GroovyClassLoader; import org.apache.commons.beanutils.PropertyUtils;

import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.LinkedHashMap; import java.util.Map;

public class GroovyGsonShimFactory { private Map<Class, Method> shimMethods = new LinkedHashMap<>();

private void generateGroovyProxy(Class ifaceClass) { String shimClassName = ifaceClass.getSimpleName() + "$Proxy"; String ifaceClassCanonicalName = ifaceClass.getCanonicalName(); String s = "import com.google.gson.;\n" + "import org.apache.commons.beanutils.BeanUtils;\n" + "import java.lang.reflect.;\n" + "import java.util.*;\n\n" + "public class "+shimClassName+" implements "+ifaceClassCanonicalName+" {\n" ;

{
  PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(ifaceClass);
  for (PropertyDescriptor p : propertyDescriptors) {
    String name = p.getName();
    String tname = p.getPropertyType().getCanonicalName();
    s += "public " + tname + " " + name + ";\n";
    s += " " + p.getReadMethod().toGenericString().replace("abstract", "").replace(ifaceClassCanonicalName + ".", "") + "{return " + name + ";};\n";
    Method writeMethod = p.getWriteMethod();
    if (writeMethod != null)
      s += " " + writeMethod.toGenericString().replace("abstract", "").replace(ifaceClassCanonicalName + ".", "").replace(")", " v){" + name + "=v;};") + "\n\n";
  }
}
s+=        "  public static "+ifaceClassCanonicalName+" fromJson(String s) {\n" +
    "    return (" +ifaceClassCanonicalName+
    ")cydesign.strombolian.server.ddl.DefaultDriver.gson().fromJson(s, "+shimClassName+".class);\n" +
    "  }\n" +  
    "  static public interface foo extends InstanceCreator<"+ifaceClassCanonicalName+">, JsonSerializer<"+ifaceClassCanonicalName+">, JsonDeserializer<"+ifaceClassCanonicalName+"> {}\n" +
    "  static {\n" +
    "    cydesign.strombolian.server.ddl.DefaultDriver.builder().registerTypeAdapter("+ifaceClassCanonicalName+".class, new foo() {\n" +
    "      public "+ifaceClassCanonicalName+" deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {\n" +
    "        return context.deserialize(json, "+shimClassName+".class);\n" +
    "      }\n" +
    "\n" +
    "      public "+ifaceClassCanonicalName+" createInstance(java.lang.reflect.Type type) {\n" +
    "        try {\n" +
    "          return new "+shimClassName+"();\n" +
    "        } catch (Exception e) {\n" +
    "          e.printStackTrace(); \n" +
    "        }\n" +
    "        return null;\n" +
    "      }\n" +
    "\n" +
    "      @Override\n" +
    "      public JsonElement serialize("+ifaceClassCanonicalName+" src, Type typeOfSrc, JsonSerializationContext context) {\n" +
    "        LinkedHashMap linkedHashMap = new LinkedHashMap();\n" +
    "        try {\n" +
    "          BeanUtils.populate(src, linkedHashMap);\n" +
    "          return context.serialize(linkedHashMap);\n" +
    "        } catch (Exception e) {\n" +
    "          e.printStackTrace(); \n" +
    "        }\n" +
    "\n" +
    "        return null;\n" +
    "      }\n" +
    "    });\n" +
    "  }\n\n" +
    "};";

System.err.println("" + s);
ClassLoader parent = DefaultDriver.class.getClassLoader();
GroovyClassLoader loader = new GroovyClassLoader(parent);

final Class gClass = loader.parseClass(s);
try {
  Method shimMethod = gClass.getMethod("fromJson", String.class);
  shimMethods.put(ifaceClass, shimMethod);
} catch (NoSuchMethodException e) {
  e.printStackTrace();
}

}

public T getShim(String json, Class ifaceClass) { if (!shimMethods.containsKey(ifaceClass)) generateGroovyProxy(ifaceClass); T shim = null;//= gson().shimMethods(json, CowSchema.class); try { shim = (T) shimMethods.get(ifaceClass).invoke(null, json); } catch (IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); } return shim; } }

adamdubiel commented 10 years ago

I't been too long since i had time to develop new features in Jason and i feel like this is the day, i will look into this issue after work and post some feedback. Thanks for the tip!