Java / JAXB:根据属性将Xml解组到特定的子类 [英] Java/JAXB: Unmarshall Xml to specific subclass based on an attribute

查看:205
本文介绍了Java / JAXB:根据属性将Xml解组到特定的子类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Is it possible to use JAXB to unmarshall xml to a specific Java class based on an attribute of the xml?

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

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

I would like to have a List of Shape objects containing a triangle and a square, each with their own shape-specific attribute. IE:

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

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

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

我目前只是放一个大的Shape类中的所有属性都不太理想。

I'm currently just putting all attributes in one big "Shape" class and it's less than ideal.

如果形状正确命名为xml元素,我可以使用它,但不幸的是我不知道我控制了我正在检索的xml。

I could get this to work if the shapes were properly named xml elements, but unfortunately I don't have control of the xml I'm retrieving.

谢谢!

推荐答案

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

JAXB is a spec, specific implementations will provide extension points to do things such as this. If you are using EclipseLink JAXB (MOXy) you could modify the Shape class as follows:

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:

Then using the MOXy @XMLCustomizer you could access the InheritancePolicy and change the class indicator field from "@xsi:type" to just "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");
    }
}

您需要确保拥有jaxb。属性文件包含模型类(Shape,Square等),以及指定EclipseLink MOXy JAXB实现的以下条目:

You will need to ensure that you have a jaxb.properties file in with you model classes (Shape, Square, etc) with the following entry specifying the EclipseLink MOXy JAXB implementation:

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

}

Square

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

}

Triangle

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

}

以下是要检查的演示程序一切正常:

Below is a demo program to check that everything works:

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的更多信息,请参阅:

For more information on EclipseLink MOXy see:

  • http://www.eclipse.org/eclipselink/moxy.php

编辑

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

In EclipseLink 2.2 we're making this easier to configure, check out the following article for more information:

  • http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-moxy-extension.html

这篇关于Java / JAXB:根据属性将Xml解组到特定的子类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆