繁体   English   中英

杰克逊定制反序列化

[英]Jackson Custom Deserialize

我想反序列化我的自定义序列化对象。 我的对象基本上是一个简单的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;
}

这是结果

 [
   {
      "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和k作为json中的字段名称非常难看。 这就是我编写自定义序列化程序的原因:

@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();
}

结果正是我想要的。 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"
      }
   }
]

这是我的问题。 如何将我的json字符串反序列化为List<Pair<V, K> 真正的问题是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

   }
}

我想,您应该创建自己的PropertyNamingStrategy 例如,请参阅我的简单实现:

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;
    }
}

现在您可以这样使用它:

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输出:

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

编辑

因为我的回答并不清楚,所以我提供了完整的示例源代码,它将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 + "]";
    }
}

完整输出日志:

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

因为输出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"
      }
   }
]

如您所见,我们创建了新的JsonConverter对象,其中定义了Pair属性名称之间的映射以及我们希望在JSON字符串表示中看到的名称。 现在,如果你有例如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;
}

我正在寻找带有一些注释的答案( JsonTypeInfoJsonUnwrapped ),但这两个显然不能很好地协同工作(参见本期 )。 这将处理您的问题的序列化和反序列化部分,而不依赖于自定义de / serializer。 相反,你需要一个自定义反序列化器,它在这些行上做了一些事情:

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));
    }
}

然后,您只需要注册所需的映射

暂无
暂无

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

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