我需要序列圖包含JSON列表和地圖。每個地圖實例都包含一個UUID字段。該圖可以包含具有相同UUID的多個Map實例。具有相同UUID的地圖被認爲是相同的。- 傑克遜如何更換序列化映射
在序列化,我想更換已先前已係列化僅他們的UUID地圖實例。
什麼是實現與傑克遜最好的方法是什麼?
謝謝
我需要序列圖包含JSON列表和地圖。每個地圖實例都包含一個UUID字段。該圖可以包含具有相同UUID的多個Map實例。具有相同UUID的地圖被認爲是相同的。- 傑克遜如何更換序列化映射
在序列化,我想更換已先前已係列化僅他們的UUID地圖實例。
什麼是實現與傑克遜最好的方法是什麼?
謝謝
您可以實現圖形類的自定義序列化程序。
必須擴展StdSerializer
並覆蓋
@Override
public void serialize(T value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException
你這麼做的時候,你需要讓傑克遜知道您的序列化。您可以通過使用@JsonSerialize(using = CustomSerializer.class)
註釋您的圖表類來實現該目的,或者您可以註冊包含自定義序列化程序的新模塊。
下面是我想出了一個可行的解決方案。
然而,有一個更優雅的方式來獲得頂級連載電話(這是需要重新初始化的自定義序列化)一個生命週期掛鉤?
而且,我不相信,保持每個線程訪問對象,使用ThreadLocal的軌道,是最好的解決方案。任何建議?
感謝
public class IdentifiableSerializerTest {
public static void main(String[] args) throws JsonProcessingException {
ObjectMapper mapper = createObjectMapper();
test(mapper);
}
interface Identifiable {
Long getId();
}
public static ObjectMapper createObjectMapper() {
ObjectMapper mapper = new ObjectMapper();
// disable quoting - for testing purpose
mapper.configure(JsonGenerator.Feature.QUOTE_FIELD_NAMES, false);
mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
// register serializer for Identifiable type
SimpleModule module = new SimpleModule();
module.addSerializer(Identifiable.class, new IdentifiableSerializer(mapper.writer()));
mapper.registerModule(module);
// lifecycle hook to re-init IdentifiableSerializer on root-level serialize calls
mapper.setSerializerProvider(new IdentifiableSerializerProvider());
return mapper;
}
/**
* This class serves to intercept root-level serialize calls in order to
* clean the map of visited objects, see {@link IdentifiableSerializer#visited}.
*
* TODO: this seems lot of code just to get a hook on root-level serialize calls...
*/
public static class IdentifiableSerializerProvider extends DefaultSerializerProvider {
public IdentifiableSerializerProvider() { super(); }
protected IdentifiableSerializerProvider(SerializerProvider src, SerializationConfig config, SerializerFactory f) {
super(src, config, f);
}
@Override
public DefaultSerializerProvider createInstance(SerializationConfig config, SerializerFactory f) {
return new IdentifiableSerializerProvider(this, config, f);
}
@Override
public void serializeValue(JsonGenerator gen, Object value) throws IOException {
IdentifiableSerializer.reset();
super.serializeValue(gen, value);
}
}
public static class IdentifiableSerializer extends JsonSerializer<Identifiable> {
private static ThreadLocal<Set> visited = new ThreadLocal<Set>() {
@Override
protected Set initialValue() {
return new HashSet();
}
};
public static void reset() {
visited.get().clear();
}
private final ObjectWriter delegate;
public IdentifiableSerializer(ObjectWriter delegate) {
this.delegate = delegate;
}
@Override
public void serialize(Identifiable value, JsonGenerator jgen, SerializerProvider provider) throws IOException {
Long id = value.getId();
Set seen = visited.get();
if (seen.contains(id)) {
jgen.writeStartObject();
jgen.writeNumberField("@REF", id);
jgen.writeEndObject();
}
else {
seen.add(id);
delegate.writeValue(jgen, value);
}
}
}
static class IdentifiableMap extends HashMap implements Identifiable {
static long counter = 0;
Long id = counter++;
{
put("@ID", id);
}
@Override
public Long getId() {
return id;
}
}
public static void test(ObjectMapper mapper) throws JsonProcessingException {
Map myMap = new IdentifiableMap() {{
put("key1", 1);
put("key2", 2);
put("key3", 3);
}};
List<Map> myList = Arrays.asList(myMap, myMap);
String expected = "[{key1:1,key2:2,key3:3,@ID:0},{@REF:0}]";
String actual = mapper.writeValueAsString(myList);
Assert.assertEquals(expected, actual);
System.out.println("SUCCESS");
}
}