@XmlElementWrapper 序列化无法使用 Jackson JaxB 注释



我们使用 Jackson 2.9.4 和 JaxB 注释来序列化为 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));
}

预期输出为

{"票证":

{"票证":[3,4,5]}}

但实际输出是

{"票证":[3,4,5]}

我正在考虑使用自定义 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();

最新更新