JAXB / xjc:从子元素生成类并根据类类型加载它们

时间:2013-01-15 17:00:24

标签: java jaxb jaxb2

我有一个XML格式的配置文件,类似于:

<configuration>
     <database>
          <host></host>
          <port></port>
     </database>
     <queue>
           <host></host>
           <port></port>
           <type></type>
      </queue>
</configuration>

我想使用JAXB / xjc为此配置生成Java类,但是我想生成这些类并将这些类解组到树中。我不想接收Configuration.java,而是想要一个Database.java和Queue.java(为了将它们分别注入到Guice托管应用程序中)。我(目前)没有看到这样做的任何方式,但可能正在寻找错误的东西。


经过一些实验,我找到了一个生成这些类的解决方案,并能够根据类填充和返回这些类:

首先,我添加了一个bindings.xjb文件,该文件将生成包含的类(本例中为Database和Queue)

<jaxb:bindings
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">
    <jaxb:globalBindings localScoping="toplevel"/>
</jaxb:bindings>

但是,JAXB无法解组使用Database或Queue类,只能使用Configuration类(这可能是我可能遗漏的内容)。我能做到

JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
Configuration conf = (Configuration) um.unmarhal(xmlFile);

但不是

JAXBContext context = JAXBContext.newInstance(Database.class);
Unmarshaller um = context.createUnmarshaller();
Database db = (Database) um.unmarhal(xmlFile);

但是,因为我可以通过在Configuration对象的实例上调用getDatabase()来获取数据库对象,所以也可以使用反射使其成为通用的(使得此代码缓存结果在适当的位置是另一个练习):

    T item = null;
    try {
        JAXBContext context = JAXBContext.newInstance(Configuration.class);
        Unmarshaller um = context.createUnmarshaller();
        Configuration conf = (Configuration) um.unmarshal(xmlFile);
        Method[] allMethods = Configuration.class.getDeclaredMethods();
        for (Method method : allMethods)
        {
            if (method.getReturnType().equals(clazz))
            {
                item = (T) method.invoke(conf);
                break;
            }
        }
    } catch (JAXBException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        throw new ConfigException("Failure detected while loading configuration", e);
    }
    return item;

我不确定这是最好的解决方案(我昨天才开始使用JAXB),但似乎达到了我的目标。

2 个答案:

答案 0 :(得分:0)

我正在用问题中讨论的问题解决方案来回答这个问题。这符合我的要求:


经过一些实验,我找到了一个生成这些类的解决方案,并能够根据类填充和返回这些类:

首先,我添加了一个bindings.xjb文件,该文件将生成包含的类(本例中为Database和Queue)

<jaxb:bindings
    xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
    version="2.1">
    <jaxb:globalBindings localScoping="toplevel"/>
</jaxb:bindings>

但是,JAXB无法解组使用Database或Queue类,只能使用Configuration类(这可能是我可能遗漏的内容)。我能做到

JAXBContext context = JAXBContext.newInstance(Configuration.class);
Unmarshaller um = context.createUnmarshaller();
Configuration conf = (Configuration) um.unmarhal(xmlFile);

但不是

JAXBContext context = JAXBContext.newInstance(Database.class);
Unmarshaller um = context.createUnmarshaller();
Database db = (Database) um.unmarhal(xmlFile);

但是,因为我可以通过在Configuration对象的实例上调用getDatabase()来获取数据库对象,所以也可以使用反射使其成为通用的(使得此代码缓存结果在适当的位置是另一个练习):

    T item = null;
    try {
        JAXBContext context = JAXBContext.newInstance(Configuration.class);
        Unmarshaller um = context.createUnmarshaller();
        Configuration conf = (Configuration) um.unmarshal(xmlFile);
        Method[] allMethods = Configuration.class.getDeclaredMethods();
        for (Method method : allMethods)
        {
            if (method.getReturnType().equals(clazz))
            {
                item = (T) method.invoke(conf);
                break;
            }
        }
    } catch (JAXBException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
        throw new ConfigException("Failure detected while loading configuration", e);
    }
    return item;

这允许我通过传递Database.class来获得一个解组数据库,而无需为任何配置参数硬编码方法。然后可以在需要的地方注入这些内容,而无需注入整个未编组的XML文件。

答案 1 :(得分:0)

步骤1:创建3个类configuration.java,database.java,queue.java

configuration.java

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "configuration")
public class configuration{

  @XmlElement
  private database db;
  @XmlElement
  private queue q;
  ...
}

@XmlAccessorType(XmlAccessType.FIELD)
public class database{
  @XmlElement
  private String host;
  @XmlElement
  private String port;
....
}

-------------------------

    InputStream xmlStream = new FileInputStream(config.xml);
    JAXBContext jaxbContext = JAXBContext.newInstance(configuration.class, database.class,queue.class);
    Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
                    configuration config= (configuration) jaxbUnmarshaller.unmarshal(xmlStream);

    config.getDatabase().getHost(); //returns the host
    config.getDatabase().getPort(); //returns the port

------------------------------------