Java Generics for unmarshall JAXB Object

10,007

Solution 1

Yes, you can enhance your code a little bit:

protected static <T> T unmarshall(String xml, Class<T> clazz)
        throws JAXBException {
    JAXBContext jc = JAXBContext.newInstance(clazz);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    T obj = clazz.cast(unmarshaller.unmarshal(new StringReader(xml)));
    return obj;
}

Solution 2

If you don't need/want to reuse the JAXBContext, no need to create it. There is a convenience method that (almost) has the method signature you want. It throws a RuntimeException (many prefer that).

protected static <T> T unmarshall(String xml, Class<T> clazz) {
    return JAXB.unmarshal(new StringReader(xml), clazz);
}

But imo, just use the method directly without a wrapper.

Reusing a JAXBContext makes (un)marshalling faster in the long run. Another improvement is clazz.cast() to avoid the nasty unchecked cast

private static final ConcurrentMap<Class<?>, JAXBContext> CONTEXT = new ConcurrentHashMap<>();

protected static <T> T unmarshall(String xml, Class<T> clazz)
        throws JAXBException {
    JAXBContext context = CONTEXT.get(clazz);
    if (context == null){
        context = JAXBContext.newInstance(clazz);
        CONTEXT.putIfAbsent(clazz, context);
    }

    Unmarshaller unmarshaller = context.createUnmarshaller();
    Object obj = unmarshaller.unmarshal(new StringReader(xml));
    if (clazz.isInstance(obj)){
        return clazz.cast(obj);
    }
    throw new IllegalArgumentException("XML does not represent an instance of type:" + clazz.getName());
}
Share:
10,007
Vel
Author by

Vel

Software Engineer

Updated on June 16, 2022

Comments

  • Vel
    Vel almost 2 years

    I have the below code to unmarshall xml into Java objects. I would like to see if this code can be enhanced by using Java Generics instead of using Object type as return value.

    protected static <T> Object unmarshall(String xml, Class<T> clazz)
            throws JAXBException {
        JAXBContext jc = JAXBContext.newInstance(clazz);
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Object obj = unmarshaller.unmarshal(new StringReader(xml));
        return obj;
    }
    

    Any suggestions.

  • Vel
    Vel over 7 years
    Thanks for the input!
  • VGR
    VGR over 7 years
    SuppressWarnings is a quick-and-dirty workaround that hides programmer mistakes. Why not use the typesafe version instead: T obj = unmarshaller.unmarshal(new StreamSource(new StringReader(xml)), clazz).getValue();
  • k5_
    k5_ over 7 years
    @VGR that will bind the class to any rootelement (ignoring the actual name of the root element). Even if there is a better match in the context. A better way is to use clazz.isInstance() and clazz.cast() to avoid the unchecked cast and provide an expected result.
  • Thomas Fritsch
    Thomas Fritsch over 7 years
    edited: now avoiding ugly @SuppressWarnings by using clazz.cast()