【问题标题】:@XmlElementWrapper Serialization not working using Jackson JaxB Annotations@XmlElementWrapper 序列化无法使用 Jackson JaxB 注解
【发布时间】:2018-11-12 21:43:34
【问题描述】:

我们正在使用 Jackson 2.9.4 和 JaxB Annotations 序列化为 JSON。

@XMLElementWrapper 注释未按预期添加额外的包装级别。相反,它只是更改元素的名称。

    @XmlRootElement(name = "revision")
    class A {
        private List<Integer> tickets = Arrays.asList(3,4,5);

        @XmlElement(name = "ticket")
        @XmlElementWrapper(name = "tickets")
        public List<Integer> getTickets() { return tickets; }
    }

        public void test() throws Exception {
            ObjectMapper mapper = new ObjectMapper();
            JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();
            mapper.registerModule(jaxbAnnotationModule);
            A a = new A();
            System.out.println(mapper.writeValueAsString(a));

        }

预期输出是

{"tickets":{"ticket":[3,4,5]}}

但实际输出是

{“门票”:[3,4,5]}

【问题讨论】:

    标签: java json serialization jackson jackson2


    【解决方案1】:

    我正在考虑使用自定义 Jackson 序列化程序和自定义注释来解决此问题,该注释将指定包装层的名称。

    序列化程序需要新包装层的名称。

    用户可以使用自定义注释指定名称。

    Jackson 在序列化器工厂中创建了自定义序列化器的实例,因此我需要重写创建序列化器的函数,读取注释,并让序列化器实例知道那里指定的名称。

    我有点担心这里的脆弱性,因为压倒一切的序列化工厂根本没有很好的文档记录,而且我不确定它可能会导致什么副作用。

    public class XMLWrapperCollectionSerializer extends JsonSerializer<Collection> {
        private String innerFieldName = null;
        public void setInnerFieldName(String value) { this.innerFieldName = value; }
        public String getInnerFieldName() { return innerFieldName; }
        @Override
         public void serialize(Collection myClass, JsonGenerator generator, SerializerProvider provider) 
            throws JsonGenerationException, IOException {
            generator.writeStartObject();
            generator.writeFieldName(innerFieldName);
            provider.defaultSerializeValue(myClass, generator);
            generator.writeEndObject();
        } 
    }
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    import java.lang.annotation.ElementType;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public  @interface XMLWrapperSerializerAttributes{
      String innerFieldName();
    }
    
    public class CustomSerializerFactory extends BeanSerializerFactory {
    
        public CustomSerializerFactory() {
            super(null);
        }
    
        @Override
        protected JsonSerializer<Object> findSerializerFromAnnotation(SerializerProvider prov, Annotated a) throws JsonMappingException
        {
            JsonSerializer<Object> serializer = super.findSerializerFromAnnotation(prov,  a);
    
            Object serializerAsObject = (Object)serializer;
            if (serializerAsObject instanceof XMLWrapperCollectionSerializer )
            {
                XMLWrapperCollectionSerializer wrapperSerializer = (XMLWrapperCollectionSerializer) serializerAsObject;
                if ( ((XMLWrapperCollectionSerializer) serializerAsObject).getInnerFieldName() == null )
                {
                 XMLWrapperSerializerAttributes annotation = a.getAnnotation(XMLWrapperSerializerAttributes.class);
                 if ( annotation == null )
                    throw new RuntimeException("XMLWrapperListSerializer must have innerFieldName, by annotation or code");
                 wrapperSerializer.setInnerFieldName(annotation.innerFieldName());
                }
            }
            return serializer;
        }
    
    
    }
    @XmlRootElement(name = "revision")
    class A {
        private List<Integer> tickets = new ArrayList(Arrays.asList(3,4,5));
    
        @XMLWrapperSerializerAttributes(innerFieldName="ticket")
        @JsonSerialize(using=XMLWrapperCollectionSerializer.class)
        @XmlElementWrapper(name = "tickets")
        @XmlElement(name = "ticket")
        public List<Integer> getTickets() { return tickets; }
    
    public class XMLElementWrapperTest{
    
        @Test
        public void test() throws Exception {
            ObjectMapper mapper = new ObjectMapper();
            mapper.setSerializerFactory(new CustomSerializerFactory());
            JaxbAnnotationModule jaxbAnnotationModule = new JaxbAnnotationModule();
            mapper.registerModule(jaxbAnnotationModule);
            A a = new A();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-01-08
      • 2011-03-19
      • 2012-12-01
      • 2015-04-03
      • 2017-01-11
      • 2016-04-25
      • 2015-10-02
      相关资源
      最近更新 更多