0

I have a configuration file in XML, which looks something like:

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

I would like to use JAXB/xjc to generate Java classes for this configuration, however I would like to generate these classes and unmarshal these one level into the tree. Rather than receiving a Configuration.java, I would like a Database.java and Queue.java (in order that these can be separately injected into a Guice managed application). I don't (currently) see any way of doing this, however may be searching for the wrong things.


After some experimentation, I have found a solution to generate these classes and be able to populate and return these based on class:

First, I added a bindings.xjb file which will generate the contained classes (Database and Queue in this example)

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

However, JAXB can't unmarshall using the Database or Queue class, only the Configuration class (this is where I may have missed something). I can do

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

but not

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

However, because I can get the database object by calling getDatabase() on an instance of the Configuration object, this can also be made generic using reflection (making this code cache results in the appropriate places is another exercise):

    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;

I'm not sure this is the best solution (I only started working with JAXB yesterday), but seems to fulfill my goal.

4

3 回答 3

0

该特定 XML 将对应于具有类型和Configuration属性的类。这不是你要找的吗?DatabaseQueue

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Configuration {

    private Database database;
    private Queue queue;

}
于 2013-01-15T17:45:47.490 回答
0

Step1:创建3个类configuration.java、database.java、queue.java

配置.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

------------------------------------
于 2015-03-02T15:50:41.480 回答
0

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


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

首先,我添加了一个 bindings.xjb 文件,它将生成包含的类(本例中的数据库和队列)

<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 文件。

于 2013-01-17T10:48:24.520 回答