Sam Goldberg
Sam Goldberg

Reputation: 6801

Java: reading Xml configuration and applying to an object, what's a lightweight, simple solution

In our various applications, we have a hodge-podge of different methods used to read Xml configuration info and apply it to a Java object.

I am looking for a utility that, when given some Xml element, will automatically take any child element and set a corresponding property on the object to be configured (and of course handle any data conversion from String to correct standard Java data type).

I realize I am describing something a lot like JAXB (which I've used only a little, as part of a project to serialize/deserialize objects to Xml), so maybe it's the best solution? I just don't particularly want to be required to add the annotations to the class, and would rather it be assumed that any setter corresponds to any similarly named Xml element.

Any recommendations on what should be a standard way to do this would be appreciated. (And I'm fine if people say go back and read the JAXB docs, because that's the best solution.)

Thanks in advance.

Update: I did end up with JAXB, although it wasn't exactly painless. The main downside is that it is not case-insensitive (when you are dealing with config files, it's best not to require match by case). One other downsides are that you need to deploy 3 additional jars. I ended up with this code (maybe there is something more elegant):

public class JAXBConfigurator<T> {

private String filePath;
private Class<T> clazz;
public JAXBConfigurator(Class<T> toConfigure, String xmlFilePath) {
    this.clazz = toConfigure;
    this.filePath = xmlFilePath;
}

/**
 * @return Parses Xml and reads configuration from Document element. Using this method assumes that the
 * configuration xml starts at the top of the xml document.
 * @throws Exception
 */
public T createAndConfigure() throws Exception {
    return createAndConfigure(null);
}

/**
 * Selects specified element from the parsed Xml document to use as the base
 * for reading the configuration.
 * 
 * @param tagName
 * @return
 */
public T createAndConfigure(String tagName) throws Exception {
    Document doc = XmlUtils.parse(filePath);
    Node startNode;
    if (tagName == null) {
        startNode = doc;
    } else {
        startNode = XmlUtils.findFirstElement(doc, tagName);
    }

    return readConfigFromNode(startNode);
}

private T readConfigFromNode(Node startNode) throws JAXBException {
    JAXBContext context = JAXBContext.newInstance(clazz);
    Unmarshaller unmarshaller = context.createUnmarshaller();
    JAXBElement<T> configElement = unmarshaller.unmarshal(startNode, clazz);
    return configElement.getValue();
}

}

The class gets used like this:

JAXBConfigurator<MyConfig> configurator = new JAXBConfigurator<Config>(MyConfig.class, xmlfilePath);
instance = configurator.createAndConfigure("MyXmlStartTag");

...which seems reusable enough for most scenarios. Thanks again to everyone who responded.

Upvotes: 2

Views: 526

Answers (2)

edwardw
edwardw

Reputation: 14002

Pick one of these: Castor, XMLBeans, JiBX, XStream and JAXB. I'd recommend JAXB or JiBX. And in case you use Spring for other purpose, you can also check out Spring Object/XML mapping, which is basically a wrapper around aforementioned implementations and provides a consistent API.

Upvotes: 2

bdoughan
bdoughan

Reputation: 149037

JAXB (JSR-222) is configuration by exception. This means that no annotations are required. You just need to add metadata to override the default rules:

For an Example

Upvotes: 3

Related Questions