Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Jackson-如何替换序列化映射_Java_Jackson - Fatal编程技术网

Java Jackson-如何替换序列化映射

Java Jackson-如何替换序列化映射,java,jackson,Java,Jackson,我需要将一个包含列表和映射的图形序列化为JSON。每个映射实例都包含一个UUID字段。该图可以包含多个具有相同UUID的映射实例。具有相同UUID的映射被认为是相同的 在序列化过程中,我希望替换以前仅由其UUID序列化的映射实例 与杰克逊一起实现这一目标的最佳方式是什么 谢谢您可以为图形类实现自定义序列化程序 public class IdentifiableSerializerTest { public static void main(String[] args) throws J

我需要将一个包含列表和映射的图形序列化为JSON。每个映射实例都包含一个UUID字段。该图可以包含多个具有相同UUID的映射实例。具有相同UUID的映射被认为是相同的

在序列化过程中,我希望替换以前仅由其UUID序列化的映射实例

与杰克逊一起实现这一目标的最佳方式是什么


谢谢

您可以为图形类实现自定义序列化程序

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

}
您必须扩展StdSerializer并覆盖

@Override
public void serialize(T value, JsonGenerator jgen, SerializerProvider provider) 
  throws IOException, JsonProcessingException

当你这么做的时候,你需要让jackson知道你的连载程序。您可以通过使用
@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");
    }

}
公共类IdentifiableSerializerTest{
公共静态void main(字符串[]args)引发JsonProcessingException{
ObjectMapper映射器=createObjectMapper();
测试(制图员);
}
接口可识别{
长getId();
}
公共静态对象映射器createObjectMapper(){
ObjectMapper mapper=新的ObjectMapper();
//禁用报价-用于测试目的
配置(JsonGenerator.Feature.QUOTE\u字段名称,false);
configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true);
//可识别类型的注册序列化程序
SimpleModule=新的SimpleModule();
module.addSerializer(identificatable.class,新的identificatableSerializer(mapper.writer());
映射器注册表模块(模块);
//在根级别序列化调用上重新初始化IdentifiableSerializer的生命周期挂钩
setSerializerProvider(新的可识别SerializerProvider());
返回映射器;
}
/**
*此类用于拦截根级别的序列化调用,以便
*清理访问对象的映射,请参阅{@link-identiableserializer#visted}。
*
*TODO:这似乎有很多代码只是为了在根级别序列化调用上获得一个钩子。。。
*/
公共静态类IdentifiableSerializerProvider扩展了DefaultSerializerProvider{
公共可标识SerializerProvider(){super();}
受保护的可标识SerializerProvider(SerializerProvider src、SerializationConfig配置、SerializerFactory f){
超级(src,config,f);
}
@凌驾
公共DefaultSerializerProvider createInstance(SerializationConfig配置,SerializerFactory f){
返回新的IdentifiableSerializerProvider(this,config,f);
}
@凌驾
公共void序列化值(JsonGenerator gen,对象值)引发IOException{
IdentifiableSerializer.reset();
super.value(gen,value);
}
}
公共静态类IdentifiableSerializer扩展了JsonSerializer{
访问的私有静态ThreadLocal=新建ThreadLocal(){
@凌驾
受保护的集合初始值(){
返回新的HashSet();
}
};
公共静态无效重置(){
已访问。获取()。清除();
}
私人代表;
公共可标识序列化程序(ObjectWriter委托){
this.delegate=委托;
}
@凌驾
public void serialize(可识别值、JsonGenerator jgen、SerializerProvider提供程序)引发IOException{
Long id=value.getId();
Set seen=visted.get();
如果(见。包含(id)){
jgen.writeStartObject();
jgen.writeNumberField(“@REF”,id);
jgen.writeEndObject();
}
否则{
见。添加(id);
delegate.writeValue(jgen,value);
}
}
}
静态类IdentifiableMap扩展HashMap实现可识别{
静态长计数器=0;
长id=计数器++;
{
put(“@ID”,ID);
}
@凌驾
公共长getId(){
返回id;
}
}
公共静态无效测试(ObjectMapper映射器)抛出JsonProcessingException{
Map myMap=新的可识别地图(){{
放置(“键1”,1);
放置(“键2”,2);
放置(“键3”,3);
}};
List myList=Arrays.asList(myMap,myMap);
字符串应为=“[{key1:1,key2:2,key3:3,@ID:0},{@REF:0}]”;
String actual=mapper.writeValueAsString(myList);
Assert.assertEquals(预期、实际);
System.out.println(“成功”);
}
}