Advertisement
Guest User

SO question (Jackson & Wrapper)

a guest
Sep 4th, 2018
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.58 KB | None | 0 0
  1. import com.fasterxml.jackson.annotation.JsonCreator;
  2. import com.fasterxml.jackson.annotation.JsonProperty;
  3. import com.fasterxml.jackson.annotation.JsonTypeInfo;
  4. import com.fasterxml.jackson.core.JsonGenerator;
  5. import com.fasterxml.jackson.core.JsonParser;
  6. import com.fasterxml.jackson.core.JsonProcessingException;
  7. import com.fasterxml.jackson.core.type.WritableTypeId;
  8. import com.fasterxml.jackson.databind.DeserializationContext;
  9. import com.fasterxml.jackson.databind.ObjectMapper;
  10. import com.fasterxml.jackson.databind.SerializerProvider;
  11. import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
  12. import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
  13. import com.fasterxml.jackson.databind.module.SimpleModule;
  14. import com.fasterxml.jackson.databind.ser.std.StdSerializer;
  15.  
  16. import java.io.IOException;
  17. import java.util.ArrayList;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21.  
  22. import static com.fasterxml.jackson.core.JsonToken.START_OBJECT;
  23.  
  24. //for tests, simple run...
  25.     class ProblematicClass {
  26.         private Map<String, Object> map;
  27.  
  28.         public ProblematicClass() {
  29.             this.map = new HashMap<>();
  30.         }
  31.  
  32.         public Boolean isEmpty() {
  33.             return map.isEmpty();
  34.         }
  35.  
  36.         public Map<String, Object> getMap() {
  37.             return map;
  38.         }
  39.  
  40.         public ProblematicClass put(String key, String value) {
  41.             map.put(key, value);
  42.             return this;
  43.         }
  44.  
  45.         public ProblematicClass put(String key, Integer value) {
  46.             map.put(key, value);
  47.             return this;
  48.         }
  49.         //put (..., boolean), put (..., Float) etc.
  50.  
  51.         public String toJson() throws JsonProcessingException {
  52.             //e.g. some internal logic (as for JsonObject)
  53.             //this is just example (I know that everything is written as string)
  54.             ObjectMapper mapper = new ObjectMapper();
  55.             return mapper.writeValueAsString(map);
  56.         }
  57.  
  58.         public static ProblematicClass fromJson(String json) throws IOException {
  59.             ProblematicClass instance = new ProblematicClass();
  60.             ObjectMapper mapper = new ObjectMapper();
  61.             instance.map = (Map<String, Object>) mapper.readValue(json, Map.class);
  62.             return instance;
  63.         }
  64.         //getString, getInteger, getFloat etc.
  65.     }
  66.  
  67.     class Wrapper<T> {
  68.         @JsonProperty("info")
  69.         private String someInfo;
  70.         @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "@class")
  71.         private List<T> data;
  72.  
  73.         @JsonCreator
  74.         public Wrapper(@JsonProperty("info") String someInfo, @JsonProperty("data") List<T> data) {
  75.             this.someInfo = someInfo;
  76.             this.data = data;
  77.         }
  78.  
  79.         public static <T> Wrapper<T> fromJson(String json) {
  80.             if (json == null) {
  81.                 return null;
  82.             }
  83.             ObjectMapper mapper = new ObjectMapper();
  84.             SimpleModule module = new SimpleModule();
  85.             //in test, I've hard coded deserializer for ProblematicClass
  86.             module.addDeserializer(ProblematicClass.class, new ProblematicClassDeserializer());
  87.             mapper.registerModule(module);
  88.  
  89.             try {
  90.                 return mapper.readValue(json, Wrapper.class);
  91.             } catch (IOException e) {
  92.                 throw new IllegalArgumentException("Cannot deserialize Wrapper from Json. Message: " + e.getMessage(), e);
  93.             }
  94.         }
  95.  
  96.         public String toJson() {
  97.             ObjectMapper mapper = new ObjectMapper();
  98.             SimpleModule module = new SimpleModule();
  99.             //in test, I've hard coded deserializer for ProblematicClass
  100.             module.addSerializer(ProblematicClass.class, new ProblematicClassSerializer());
  101.             mapper.registerModule(module);
  102.             try {
  103.                 return mapper.writeValueAsString(this);
  104.             } catch (JsonProcessingException e) {
  105.                 throw new IllegalStateException("Cannot serialize Wrapper to Json. Message: " + e.getMessage(), e);
  106.             }
  107.         }
  108.     }
  109.  
  110.     class ProblematicClassSerializer extends StdSerializer<ProblematicClass> {
  111.         public ProblematicClassSerializer() {
  112.             this(null);
  113.         }
  114.  
  115.         protected ProblematicClassSerializer(Class<ProblematicClass> t) {
  116.             super(t);
  117.         }
  118.  
  119.         @Override
  120.         public void serializeWithType(ProblematicClass value, JsonGenerator gen, SerializerProvider serializers, TypeSerializer typeSer) throws IOException {
  121.             WritableTypeId typeId = typeSer.typeId(value, START_OBJECT);
  122.             typeSer.writeTypePrefix(gen, typeId);
  123.             gen.writeFieldName("@json");
  124.             serialize(value, gen, serializers);  //our custom serialize method written below
  125.             typeSer.writeTypeSuffix(gen, typeId);
  126.         }
  127.  
  128.         @Override
  129.         public void serialize(ProblematicClass value, JsonGenerator jgen, SerializerProvider serializerProvider) throws IOException {
  130.             jgen.writeRawValue(value == null ? null : value.toJson());
  131.         }
  132.     }
  133.  
  134.     class ProblematicClassDeserializer extends StdDeserializer<ProblematicClass> {
  135.         public ProblematicClassDeserializer() {
  136.             this(null);
  137.         }
  138.  
  139.         protected ProblematicClassDeserializer(Class<?> vc) {
  140.             super(vc);
  141.         }
  142.  
  143.         @Override
  144.         public ProblematicClass deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
  145.             String json = jsonParser.getCodec().readTree(jsonParser).toString(); //this is actual json representation
  146.             ObjectMapper mapper = new ObjectMapper();
  147.             Map<String, Object> map = mapper.readValue(json, Map.class); //I know this is redundant, but for example it is fine
  148.             return json == null ? null : ProblematicClass.fromJson(mapper.writeValueAsString(map.get("@json")));
  149.             //sometimes I got {"key": "value"} //when serialize is called (ProblematicClass wrapped)
  150.             //and sometimes I got {"@json": {"key": "value"}} //when using bare ProblematicClass as in Wrapper<ProblematicClass>
  151.             //I need to distinguish these two cases but I don't know when is te first and when second
  152.             //because deserializationContext is not giving me these information
  153.         }
  154.     }
  155.  
  156.     class SomeRealClass {
  157.         public ProblematicClass problematicClass = ProblematicClass.fromJson("{\"a\": \"10\"}");
  158.         public Integer i1 = 10, i2 = 20;
  159.  
  160.         SomeRealClass() throws IOException {
  161.         }
  162.     }
  163.  
  164. public class TestMain {
  165.     public static void main(String[] args) throws IOException {
  166.         //without (de)serializes this does not work as it's json is not deserializable (because of 'empty' key)
  167.         //   {"data":[{"@class":"com.test.ProblematicClass","map":{"a":"10"},"empty":false},
  168.         //     {"@class":"com.test.ProblematicClass","map":{"b":"20"},"empty":false}],"info":"info"}
  169.         //when I hardcode (de)serializer then this (correct) json is produced:
  170.         //   {"info":"info","data":[{"@class":"com.test.ProblematicClass","@json":{"a":"10"}},
  171.         //     {"@class":"com.test.ProblematicClass","@json":{"b":"20"}}]}
  172.         {
  173.             List<ProblematicClass> list = new ArrayList<>();
  174.             list.add(ProblematicClass.fromJson("{\"a\": \"10\"}"));
  175.             list.add(ProblematicClass.fromJson("{\"b\": \"20\"}"));
  176.             Wrapper<ProblematicClass> wrapper = new Wrapper<>("info", list);
  177.             String json = wrapper.toJson();
  178.             Wrapper<ProblematicClass> copy = Wrapper.fromJson(json);
  179.         }
  180.         //---------------------------------------------------------
  181.         //but, when container class is used (SomeRealClass)
  182.         //this @json is redundant, so I wrote it only in serializeWithType
  183.         //resulting JSON is correct? there is no @json, like: "problematicClass": {"@json": {"a": "10}}
  184.         //and deserialization fails (map.get("@json") is null)
  185.         //    {"info":"info-real","data":[{"@class":"com.test.SomeRealClass","problematicClass":{"a":"10"},"i1":10,"i2":20},
  186.         //       {"@class":"com.test.SomeRealClass","problematicClass":{"a":"10"},"i1":10,"i2":20}]}
  187.         {
  188.             List<SomeRealClass> list = new ArrayList<>();
  189.             list.add(new SomeRealClass());
  190.             list.add(new SomeRealClass());
  191.             Wrapper<SomeRealClass> wrapper = new Wrapper<>("info-real", list);
  192.             String json = wrapper.toJson();
  193.             Wrapper<SomeRealClass> copy = Wrapper.fromJson(json);
  194.         }
  195.     }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement