001package fr.aumgn.dac2.arena.regions; 002 003import java.io.IOException; 004import java.lang.reflect.Constructor; 005import java.lang.reflect.InvocationTargetException; 006import java.util.HashMap; 007import java.util.Map; 008 009import com.google.gson.Gson; 010import com.google.gson.TypeAdapter; 011import com.google.gson.TypeAdapterFactory; 012import com.google.gson.reflect.TypeToken; 013import com.google.gson.stream.JsonReader; 014import com.google.gson.stream.JsonToken; 015import com.google.gson.stream.JsonWriter; 016 017import fr.aumgn.dac2.shape.ArbitraryFlatShape; 018import fr.aumgn.dac2.shape.CuboidShape; 019import fr.aumgn.dac2.shape.CylinderShape; 020import fr.aumgn.dac2.shape.EllipsoidShape; 021import fr.aumgn.dac2.shape.PolygonalShape; 022import fr.aumgn.dac2.shape.Shape; 023import fr.aumgn.dac2.shape.ShapeName; 024 025public class GsonRegionFactory implements TypeAdapterFactory { 026 027 private static final Map<String, Class<? extends Shape>> classes = 028 new HashMap<String, Class<? extends Shape>>(); 029 030 public static void registerShape(Class<? extends Shape> shapeClass) { 031 ShapeName annotation = shapeClass.getAnnotation(ShapeName.class); 032 if (annotation == null) { 033 return; 034 } 035 036 classes.put(annotation.value(), shapeClass); 037 } 038 039 static { 040 registerShape(CuboidShape.class); 041 registerShape(CylinderShape.class); 042 registerShape(PolygonalShape.class); 043 registerShape(EllipsoidShape.class); 044 registerShape(ArbitraryFlatShape.class); 045 } 046 047 private static class RegionTypeAdapter extends TypeAdapter<Region> { 048 049 private final Gson gson; 050 private final Constructor<Region> ctor; 051 052 public RegionTypeAdapter(Gson gson, Constructor<Region> ctor) { 053 this.gson = gson; 054 this.ctor = ctor; 055 } 056 057 @Override 058 public Region read(JsonReader reader) throws IOException { 059 reader.beginObject(); 060 061 reader.nextName(); 062 String type = reader.nextString(); 063 Class<? extends Shape> clazz = classes.get(type); 064 if (clazz == null) { 065 while (reader.peek() != JsonToken.END_OBJECT) { 066 reader.nextName(); 067 reader.skipValue(); 068 } 069 reader.endObject(); 070 071 return null; 072 } 073 074 reader.nextName(); 075 Shape shape = gson.fromJson(reader, clazz); 076 reader.endObject(); 077 078 try { 079 return ctor.newInstance(shape); 080 } catch (IllegalArgumentException _) { 081 } catch (InstantiationException _) { 082 } catch (IllegalAccessException _) { 083 } catch (InvocationTargetException _) { 084 } 085 086 return null; 087 } 088 089 @Override 090 public void write(JsonWriter writer, Region region) 091 throws IOException { 092 Shape shape = region.getShape(); 093 ShapeName annotation = shape.getClass() 094 .getAnnotation(ShapeName.class); 095 if (annotation == null) { 096 writer.nullValue(); 097 return; 098 } 099 String shapeName = annotation.value(); 100 101 writer.beginObject(); 102 writer.name("shape"); 103 writer.value(shapeName); 104 writer.name("data"); 105 gson.toJson(shape, shape.getClass(), writer); 106 writer.endObject(); 107 } 108 } 109 110 @SuppressWarnings("unchecked") 111 @Override 112 public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) { 113 if (!Region.class.isAssignableFrom(type.getRawType())) { 114 return null; 115 } 116 117 try { 118 Constructor<Region> ctor = (Constructor<Region>) 119 type.getRawType().getDeclaredConstructor(Shape.class); 120 ctor.setAccessible(true); 121 return (TypeAdapter<T>) new RegionTypeAdapter(gson, ctor) 122 .nullSafe(); 123 } catch (SecurityException _) { 124 } catch (NoSuchMethodException _) { 125 } 126 127 return null; 128 } 129}