簡體   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