I get what you are trying to do here and I had the same problem.
I finished writing a simple abstract class
public abstract class TypedJsonizable extends Jsonizable {}
and register TypeHierarchy adapter in my Gson instance
protected static Gson gson = new GsonBuilder() .registerTypeHierarchyAdapter (TypedJsonizable.class,new TypedJsonizableSerializer());
The key for this TypeAdapter should not call context.serialize and context.deserialize, because it will lead to the endless loop pointed out by Jeff Bowman in his answer, This is To avoid this, use the TypeAdapter.
import com.google.gson.*; import org.apache.log4j.Logger; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Type; public class TypedJsonizableSerializer implements JsonSerializer<TypedJsonizable>, JsonDeserializer<TypedJsonizable> { static final String CLASSNAME_FIELD = "_className"; Logger logger = Logger.getLogger(TypedJsonizable.class); @Override public JsonElement serialize(TypedJsonizable src, Type typeOfSrc, JsonSerializationContext context) { JsonObject contentObj = new JsonObject(); contentObj.addProperty(CLASSNAME_FIELD,src.getClass().getCanonicalName()); for (Field field : src.getClass().getDeclaredFields()) { field.setAccessible(true); try { if (field.get(src)!=null) contentObj.add(field.getName(),context.serialize(field.get(src))); } catch (IllegalAccessException e) { logger.error(e.getMessage(),e); } } return contentObj; } @Override public TypedJsonizable deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); String className = jsonObject.get(CLASSNAME_FIELD).getAsString(); if (className == null || className.isEmpty()) throw new JsonParseException("Cannot find _className field. Probably this instance has not been serialized using Jsonizable jsonizer"); try { Class<?> clazz = Class.forName(className); Class<?> realClazz = (Class<?>) typeOfT; if (!realClazz.equals(clazz)) throw new JsonParseException(String.format("Cannot serialize object of class %s to %s", clazz.getCanonicalName(),realClazz.getCanonicalName())); Object o = clazz.getConstructor().newInstance(); for (Field field : o.getClass().getDeclaredFields()) { field.setAccessible(true); if (jsonObject.has(field.getName())) { field.set(o,context.deserialize(jsonObject.get(field.getName()) , field.getGenericType())); } } return (TypedJsonizable) o; } catch (ClassNotFoundException e) { throw new JsonParseException(String.format("Cannot find class with name %s . Maybe the class has been refactored or sender and receiver are not using the same jars",className)); } catch (IllegalAccessException e){ throw new JsonParseException(String.format("Cannot deserialize, got illegalAccessException %s ",e.getMessage())); } catch (NoSuchMethodException | InstantiationException | InvocationTargetException e) { throw new JsonParseException(String.format("Cannot deserialize object of class %s, unable to create a new instance invoking empty constructor",className)); } }
}
user2858970 Jun 16 '17 at 11:19 on 2017-06-16 11:19
source share