Jackson Custom Deserialize

I would like to deserialize my custom serialized objects. My objects basically consist of a simple Pair implementation.

class School{ Integer id; String schoolName; } class Student{ Integer id; Integer schoolId; String studentName; } @JsonSerialize(using=PairSerializer.class) public class Pair<V,K>{ V v; K k; } 

Here is the result

  [ { "v":{ "id":1, "schoolId":3, "studentName":"O. Bas" }, "k":{ "id":3, "schoolName":"School 3" } }, { "v":{ "id":2, "schoolId":3, "studentName":"C. Koc" }, "k":{ "id":3, "schoolName":"School 3" } } ] 

v and k as a field name in json are pretty ugly. This is why I wrote my own serializer:

 @Override public void serialize(Pair pair, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException { jsonGenerator.writeStartObject(); jsonGenerator.writeObjectField(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL,pair.getK().getClass().getSimpleName() ), pair.getK()); jsonGenerator.writeObjectField(CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL,pair.getV().getClass().getSimpleName() ), pair.getV()); jsonGenerator.writeEndObject(); } 

The result is exactly what I want. The field names v and k are replaced with class names.

 [ { "school":{ "id":3, "schoolName":"School 3" }, "student":{ "id":1, "schoolId":3, "studentName":"O. Bas" } }, { "school":{ "id":3, "schoolName":"School 3" }, "student":{ "id":2, "schoolId":3, "studentName":"C. Koc" } } ] 

Here is my question. How can I deserialize my json string to List<Pair<V, K> ? The real problem is that V and K depend on the deserialized context, which may vary depending on the implementation of Student, School or another pair.

 public class PairDeserializer extends JsonDeserializer<Pair> { public PairDeserializer() { } @Override public Pair deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { // I need to Deserialized generic type information of Pair } } 
+4
source share
2 answers

I think you should create your own PropertyNamingStrategy . For example, see My simple implementation:

 class MapTransformNamingStrategy extends LowerCaseWithUnderscoresStrategy { private static final long serialVersionUID = 1L; private Map<String, String> mapping; public MapTransformNamingStrategy(Map<String, String> mapping) { this.mapping = mapping; } @Override public String translate(String property) { if (mapping.containsKey(property)) { return mapping.get(property); } return property; } } 

Now you can use it as follows:

 Map<String, String> mapping = new HashMap<String, String>(); mapping.put("k", "student"); mapping.put("v", "school"); ObjectMapper objectMapper = new ObjectMapper(); objectMapper.setPropertyNamingStrategy(new MapTransformNamingStrategy(mapping)); //etc 

JSON output example:

 { "school" : { "id" : 1, "schoolName" : "The Best School in the world" }, "student" : { "id" : 1, "schoolId" : 1, "studentName" : "Arnold Shwarz" } } 

EDIT

Since my answer is not clear to everyone, I present a complete source code example that serializes Java POJO objects into JSON and vice versa.

 import java.io.StringWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.PropertyNamingStrategy.LowerCaseWithUnderscoresStrategy; public class JacksonProgram { @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { List<Pair<Student, School>> pairs = createDataForSerialization(); Map<String, String> mapping = createSchoolStudentMapping(); JsonConverter jsonConverter = new JsonConverter(mapping); String json = jsonConverter.toJson(pairs); System.out.println("JSON which represents list of pairs:"); System.out.println(json); List<Pair<Student, School>> value = jsonConverter.fromJson(json, List.class); System.out.println("----"); System.out.println("Deserialized version:"); System.out.println(value); } private static Map<String, String> createSchoolStudentMapping() { Map<String, String> mapping = new HashMap<String, String>(); mapping.put("k", "student"); mapping.put("v", "school"); return mapping; } private static List<Pair<Student, School>> createDataForSerialization() { List<Pair<Student, School>> pairs = new ArrayList<Pair<Student, School>>(); pairs.add(new Pair<Student, School>(new Student(1, 3, "O. Bas"), new School(3, "School 3"))); pairs.add(new Pair<Student, School>(new Student(2, 4, "C. Koc"), new School(4, "School 4"))); return pairs; } } class JsonConverter { private Map<String, String> mapping; private ObjectMapper objectMapper; private JsonFactory jsonFactory; public JsonConverter(Map<String, String> mapping) { this.mapping = mapping; initJsonObjects(); } private void initJsonObjects() { objectMapper = new ObjectMapper(); objectMapper.setPropertyNamingStrategy(new MapTransformNamingStrategy(mapping)); jsonFactory = new JsonFactory(); } public String toJson(Object object) throws Exception { StringWriter stringWriter = new StringWriter(); JsonGenerator jsonGenerator = jsonFactory.createGenerator(stringWriter); objectMapper.writeValue(jsonGenerator, object); return stringWriter.toString(); } public <T> T fromJson(String json, Class<T> expectedType) throws Exception { JsonParser jsonParser = jsonFactory.createJsonParser(json); return objectMapper.readValue(jsonParser, expectedType); } } class MapTransformNamingStrategy extends LowerCaseWithUnderscoresStrategy { private static final long serialVersionUID = 1L; private Map<String, String> mapping; public MapTransformNamingStrategy(Map<String, String> mapping) { this.mapping = mapping; } @Override public String translate(String property) { if (mapping.containsKey(property)) { return mapping.get(property); } return property; } } class School { private Integer id; private String schoolName; public School() { } public School(Integer id, String schoolName) { this.id = id; this.schoolName = schoolName; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getSchoolName() { return schoolName; } public void setSchoolName(String schoolName) { this.schoolName = schoolName; } @Override public String toString() { return "School [id=" + id + ", schoolName=" + schoolName + "]"; } } class Student { private Integer id; private Integer schoolId; private String studentName; public Student() { } public Student(Integer id, Integer schoolId, String studentName) { this.id = id; this.schoolId = schoolId; this.studentName = studentName; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public Integer getSchoolId() { return schoolId; } public void setSchoolId(Integer schoolId) { this.schoolId = schoolId; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } @Override public String toString() { return "Student [id=" + id + ", schoolId=" + schoolId + ", studentName=" + studentName + "]"; } } class Pair<V, K> { private V v; private K k; public Pair() { } public Pair(V v, K k) { this.v = v; this.k = k; } public V getV() { return v; } public void setV(V v) { this.v = v; } public K getK() { return k; } public void setK(K k) { this.k = k; } @Override public String toString() { return "Pair [v=" + v + ", k=" + k + "]"; } } 

Full output log:

 JSON which represents list of pairs: [{"school":{"id":1,"schoolId":3,"studentName":"O. Bas"},"student":{"id":3,"schoolName":"School 3"}},{"school":{"id":2,"schoolId":4,"studentName":"C. Koc"},"student":{"id":4,"schoolName":"School 4"}}] ---- Deserialized version: [{school={id=1, schoolId=3, studentName=O. Bas}, student={id=3, schoolName=School 3}}, {school={id=2, schoolId=4, studentName=C. Koc}, student={id=4, schoolName=School 4}}] 

Since the output JSON is not formatted, I present it in a more understandable version:

 [ { "school":{ "id":1, "schoolId":3, "studentName":"O. Bas" }, "student":{ "id":3, "schoolName":"School 3" } }, { "school":{ "id":2, "schoolId":4, "studentName":"C. Koc" }, "student":{ "id":4, "schoolName":"School 4" } } ] 

As you can see, we are creating a new JsonConverter object with a mapping between the Pair property names and the names that we want to see in the JSON string representation. Now, if you have, for example, Pair<School, Room> , you can create a mapping map as follows:

 private static Map<String, String> createSchoolRoomMapping() { Map<String, String> mapping = new HashMap<String, String>(); mapping.put("k", "school"); mapping.put("v", "room"); return mapping; } 
+1
source

I was going to get an answer with some annotation ( JsonTypeInfo and JsonUnwrapped ), but the two do not work well together (see this question ). This will be related to both serialization and deserialization of your problem, without relying on custom de / serializer. Instead, you'll need a custom deserializer that does something along this line:

 class PairDeserializer extends JsonDeserializer<Pair>{ static Map<String, Class> MAPPINGS = new HashMap<String, Class>(); @Override public Pair deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException { Object key = deserializeField(jp); Object value = deserializeField(jp); Pair pair = new Pair(); pair.k = key; pair.v = value; jp.nextToken(); return pair; } private Object deserializeField(JsonParser jp) throws IOException, JsonParseException, JsonProcessingException { jp.nextValue(); String className = jp.getCurrentName(); return jp.readValueAs(MAPPINGS.get(className)); } } 

Then you only need to register the mappings you need

0
source

Source: https://habr.com/ru/post/1482331/


All Articles