Jaxb使用自定义注释进行编组

我有一个要求,根据字段上标记的自定义注释来编组/解组java pojo的一些元素。 假设我的java pojp中有3个字段

@CustomVersion("v1") private String field1; @CustomVersion("v1","v2") private String field2; @CustomVersion("v2") private String field3; 

如果我在jaxb中转换时传递version =“v1”参数,我想仅使用v1对字段进行编组。 如果我通过v2,那么所有带v2注释的字段都应该被编组。

是甚至可以使用jaxb? 我确信选择性编组将通过某些图书馆或方式得到支持,经过一番搜索后我仍然无法弄明白。 任何帮助或建议或指针都非常感谢。

首先,我建议在编组之前进行这样的预处理。 这会容易得多。 但是,如果由于某种原因不可能,那么您可以创建自定义类型适配器。 然后,您可以在要启用版本控制的每种类型上放置@XmlJavaTypeAdapter(VersioningAdapter.class)@XmlJavaTypeAdapter也可以在包级别指定,但您必须指定它适用的类型。 如果不指定某个地方@XmlJavaTypeAdapter则无法使用@XmlJavaTypeAdapter

这种解决方案的缺点:

  • 如果您有多个版本化类型,则每个类型都必须使用@XmlJavaTypeAdapter进行注释
  • @XmlJavaTypeAdapter不适用于根元素,仅适用于子元素。 您必须在编组之前在根元素上手动调用适配器

AFAIK没有其他选项来自定义JAXB编组。 这就是为什么我认为注释处理应该在编组之前在单独的步骤中执行。 除非你能接受上述限制。

示例适配器(完整代码可以在这里找到):

 public class VersioningAdapter extends XmlAdapter { @Override public Object unmarshal(Object v) throws Exception { // TODO Auto-generated method stub return null; } @Override public Object marshal(Object v) throws Exception { if (v == null) { return v; } Field[] fields = v.getClass().getDeclaredFields(); for (Field field : fields) { Annotation[] annotations = field.getDeclaredAnnotations(); CustomVersion annotation = findCustomVersion(annotations); if (annotation != null) { if (!contains(annotation, Configuration.getVersion())) { field.setAccessible(true); field.set(v, null); } } } return v; } private CustomVersion findCustomVersion(Annotation[] annotations) { for (Annotation annotation : annotations) { if (annotation instanceof CustomVersion) { return (CustomVersion) annotation; } } return null; } private boolean contains(CustomVersion annotation, String version) { String[] values = annotation.value(); for (String value : values) { if (value.equals(version)) { return true; } } return false; } } 

注意:我是EclipseLink JAXB(MOXy)的负责人,也是JAXB(JSR-222)专家组的成员。

下面是如何使用MOXy的@XmlNamedObjectGraphs扩展来映射用例的示例。

Java模型

@XmlNamedObjectGraphs扩展允许您指定由键标识的多个映射子集。

 import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlRootElement; import org.eclipse.persistence.oxm.annotations.XmlNamedAttributeNode; import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraph; import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraphs; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) @XmlNamedObjectGraphs({ @XmlNamedObjectGraph( name="v1", attributeNodes = { @XmlNamedAttributeNode("field1"), @XmlNamedAttributeNode("field2")}), @XmlNamedObjectGraph( name="v2", attributeNodes = { @XmlNamedAttributeNode("field2"), @XmlNamedAttributeNode("field3")}) }) public class Foo { private String field1 = "ONE"; private String field2 = "TWO"; private String field3 = "THREE"; } 

jaxb.properties

要将MOXy用作JAXB提供程序,您需要包含一个名为jaxb.properties的文件, jaxb.properties包含以下条目(请参阅: http : jaxb.properties ) 。

 javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

演示代码

演示

您可以指定与对象图对应的键,以将该子集应用于您正在编组的对象。

 import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; import org.eclipse.persistence.jaxb.MarshallerProperties; public class Demo { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Foo.class); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Foo foo = new Foo(); // Marshal Everything marshaller.marshal(foo, System.out); // Marshal "v1" Data marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "v1"); marshaller.marshal(foo, System.out); // Marshal "v2" Data marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "v2"); marshaller.marshal(foo, System.out); } } 

产量

   ONE TWO THREE    ONE TWO    TWO THREE  

欲获得更多信息