简体   繁体   English

杰克逊定制反序列化

[英]Jackson Custom Deserialize

I would like deserialize my custom serialized objects. 我想反序列化我的自定义序列化对象。 My objects are basically consisting a simple Pair implementation. 我的对象基本上是一个简单的Pair实现。

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 field name in json is pretty ugly. v和k作为json中的字段名称非常难看。 That is why I have written a custom serializer as this: 这就是我编写自定义序列化程序的原因:

@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. 结果正是我想要的。 v and k field names are replaced by their class names. v和k字段名称由其类名替换。

[
   {
      "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 the my question. 这是我的问题。 How can I deserialize my json string to List<Pair<V, K> ? 如何将我的json字符串反序列化为List<Pair<V, K> The real problem is that V and K are depends on the deserialized context it might vary as Student, School or another pair implementation. 真正的问题是V和K取决于反序列化的上下文,它可能会随学生,学校或另一对实现而变化。

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

   }
}

I think, you should create your own PropertyNamingStrategy . 我想,您应该创建自己的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 in this way: 现在您可以这样使用它:

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

Example JSON output: 示例JSON输出:

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

EDIT 编辑

Because my answer is not clear for everyone I present full example source code which serialize Java POJO objects into JSON and "vice versa". 因为我的回答并不清楚,所以我提供了完整的示例源代码,它将Java POJO对象序列化为JSON,反之亦然。

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 + "]";
    }
}

The 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}}]

Because the output JSON is not formatted I present it in more understandable version: 因为输出JSON没有格式化,所以我将它呈现在更易于理解的版本中:

[
   {
      "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 create new JsonConverter object with definition of mapping between Pair property names and which names we want to see in JSON string representation. 如您所见,我们创建了新的JsonConverter对象,其中定义了Pair属性名称之间的映射以及我们希望在JSON字符串表示中看到的名称。 Now if you have for example Pair<School, Room> you can create mapping Map in this way: 现在,如果你有例如Pair<School, Room>你可以用这种方式创建映射Map:

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

    return mapping;
}

I was going for an answer with some annotation ( JsonTypeInfo and JsonUnwrapped ), but those two don't work well together apparently (see this issue ). 我正在寻找带有一些注释的答案( JsonTypeInfoJsonUnwrapped ),但这两个显然不能很好地协同工作(参见本期 )。 That would of handled both the serialization and deserialization part of your problem, without relying on custom de/serializer. 这将处理您的问题的序列化和反序列化部分,而不依赖于自定义de / serializer。 Instead, you'll need a custom deserializer, which does something along those 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 然后,您只需要注册所需的映射

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM