Java/JAXB : Unmarshall Xml to specific subclass based on an attribute

标签 java inheritance jaxb eclipselink

是否可以使用 JAXB 根​​据 xml 的属性将 xml 解码为特定的 Java 类?

<shapes>
  <shape type="square" points="4" square-specific-attribute="foo" />
  <shape type="triangle" points="3" triangle-specific-attribute="bar" />
</shapes>

我想要一个包含三角形和正方形的 Shape 对象列表,每个对象都有自己特定于形状的属性。即:

abstract class Shape {
    int points;
    //...etc
}

class Square extends Shape {
    String square-specific-attribute;
    //...etc
}

class Triangle extends Shape {
    String triangle-specific-attribute;
    //...etc
}

我目前只是将所有属性放在一个大的“形状”类中,这并不理想。

如果形状被正确命名为 xml 元素,我可以让它工作,但不幸的是我无法控制我正在检索的 xml。

谢谢!

最佳答案

JAXB 是一个规范,具体的实现会提供扩展点来做这样的事情。如果您使用 EclipseLink JAXB (MOXy)您可以按如下方式修改 Shape 类:

import javax.xml.bind.annotation.XmlAttribute;
import org.eclipse.persistence.oxm.annotations.XmlCustomizer;

@XmlCustomizer(ShapeCustomizer.class)
public abstract class Shape {

    int points;

    @XmlAttribute
    public int getPoints() {
        return points;
    }

    public void setPoints(int points) {
        this.points = points;
    }

}

然后使用 MOXy @XMLCustomizer 您可以访问 InheritancePolicy 并将类指示符字段从“@xsi:type”更改为“type”:

import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;

public class ShapeCustomizer implements DescriptorCustomizer {

    @Override
    public void customize(ClassDescriptor descriptor) throws Exception {
        descriptor.getInheritancePolicy().setClassIndicatorFieldName("@type");
    }
}

您需要确保模型类(Shape、Square 等)中有一个 jaxb.properties 文件,其中包含指定 EclipseLink MOXy JAXB 实现的以下条目:

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

下面是其余的模型类:

形状

import java.util.ArrayList;
import java.util.List;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Shapes {

    private List<Shape> shape = new ArrayList<Shape>();;

    public List<Shape> getShape() {
        return shape;
    }

    public void setShape(List<Shape> shape) {
        this.shape = shape;
    }

}

正方形

import javax.xml.bind.annotation.XmlAttribute;

public class Square extends Shape {
    private String squareSpecificAttribute;

    @XmlAttribute(name="square-specific-attribute")
    public String getSquareSpecificAttribute() {
        return squareSpecificAttribute;
    }

    public void setSquareSpecificAttribute(String s) {
        this.squareSpecificAttribute = s;
    }

}

三角形

import javax.xml.bind.annotation.XmlAttribute;

public class Triangle extends Shape {
    private String triangleSpecificAttribute;

    @XmlAttribute(name="triangle-specific-attribute")
    public String getTriangleSpecificAttribute() {
        return triangleSpecificAttribute;
    }

    public void setTriangleSpecificAttribute(String t) {
        this.triangleSpecificAttribute = t;
    }

}

下面是一个演示程序,用于检查一切是否正常:

import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(Shapes.class, Triangle.class, Square.class);

        StringReader xml = new StringReader("<shapes><shape square-specific-attribute='square stuff' type='square'><points>4</points></shape><shape triangle-specific-attribute='triangle stuff' type='triangle'><points>3</points></shape></shapes>");
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Shapes root = (Shapes) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jaxbContext.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(root, System.out);
    }
}

我希望这会有所帮助。

有关 EclipseLink MOXy 的更多信息,请参阅:

编辑

在 EclipseLink 2.2 中,我们使其更易于配置,请查看以下文章了解更多信息:

关于Java/JAXB : Unmarshall Xml to specific subclass based on an attribute,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2992234/

相关文章:

java - 使用 Jersey 默认实现 : MOXy 反序列化多态类型

Java 导入,不带 CLASSPATH

java - jitpack 将构建工件下载到哪里?

具有空派生类对象的 C++ 继承大小

eclipse - 仅在 Eclipse 中获取 "The POM for <name> is invalid, transitive dependencies (if any) will not be available"

java - 如何构建图形交互的小程序?

java - 隐藏在 C# 和 Java 中的基方法

python - 如何在 Python 中将参数传递给 __metaclass__

java - 如何使用jaxb获取anyType值?

java - 在 JAXB 中创建 SOAP 属性