4

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

   }
}
4

2 回答 2

1

我认为,您应该创建自己的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;
}
于 2013-05-23T12:35:57.000 回答
0

我打算用一些注释(JsonTypeInfoJsonUnwrapped)来回答,但这两者显然不能很好地协同工作(见这个问题)。这将处理问题的序列化和反序列化部分,而不依赖于自定义反序列化器。相反,您需要一个自定义的反序列化器,它会按照这些方式执行一些操作:

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

然后你只需要注册你需要的映射

于 2013-05-24T17:52:15.647 回答