Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create a Pool of JAXB Unmarshaller

I was looking around to find a way to improve JAXB Unmarshalling performances processing huge sets of files and found the following advice:

"If you really care about the performance, and/or your application is going to read a lot of small documents, then creating Unmarshaller could be relatively an expensive operation. In that case, consider pooling Unmarshaller objects"

Googling the web to find an example of this didn't return anything, so I thought it may be of interest to put my implementation here using Spring 3.0 and Apache Commons Pool.

UnmarshallerFactory.java

import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import org.apache.commons.pool.KeyedPoolableObjectFactory;
import org.springframework.stereotype.Component;

/**
 * Pool of JAXB Unmarshallers.
 * 
 */
@Component
public class UnmarshallerFactory implements KeyedPoolableObjectFactory {
    // Map of JAXB Contexts
    @SuppressWarnings("rawtypes")
    private final static Map<Object, JAXBContext> JAXB_CONTEXT_MAP = new HashMap<Object, JAXBContext>();

    @Override
    public void activateObject(final Object arg0, final Object arg1) throws Exception {
    }

    @Override
    public void passivateObject(final Object arg0, final Object arg1) throws Exception {
    }

    @Override
    public final void destroyObject(final Object key, final Object object) throws Exception {
    }

    /**
     * Create a new instance of Unmarshaller if none exists for the specified
     * key.
     * 
     * @param unmarshallerKey
     *            : Class used to create an instance of Unmarshaller
     */
    @SuppressWarnings("rawtypes")
    @Override
    public final Object makeObject(final Object unmarshallerKey) {
        if (unmarshallerKey instanceof Class) {
            Class clazz = (Class) unmarshallerKey;
            // Retrieve or create a JACBContext for this key
            JAXBContext jc = JAXB_CONTEXT_MAP.get(unmarshallerKey);
            if (jc == null) {
                try {
                    jc = JAXBContext.newInstance(clazz);
                    // JAXB Context is threadsafe, it can be reused, so let's store it for later
                    JAXB_CONTEXT_MAP.put(unmarshallerKey, jc);
                } catch (JAXBException e) {
                    // Deal with that error here
                    return null;
                }
            }
            try {
                return jc.createUnmarshaller();
            } catch (JAXBException e) {
                // Deal with that error here
            }
        }
        return null;
    }

    @Override
    public final boolean validateObject(final Object key, final Object object) {
        return true;
    }
}

UnmarshallerPool.java

import org.apache.commons.pool.impl.GenericKeyedObjectPool;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class UnmarshallerPool extends GenericKeyedObjectPool {
    @Autowired
    public UnmarshallerPool(final UnmarshallerFactory unmarshallerFactory) {
    // Make usage of the factory created above
    super(unmarshallerFactory);
            // You'd better set the properties from a file here
    this.setMaxIdle(4);
    this.setMaxActive(5);
    this.setMinEvictableIdleTimeMillis(30000);
    this.setTestOnBorrow(false);
    this.setMaxWait(1000);
    }

    public UnmarshallerPool(UnmarshallerFactory objFactory,
        GenericKeyedObjectPool.Config config) {
        super(objFactory, config);
    }

    @Override
    public Object borrowObject(Object key) throws Exception {
        return super.borrowObject(key);
    }

    @Override
    public void returnObject(Object key, Object obj) throws Exception {
        super.returnObject(key, obj);
    }
}

And in your class that require a JAXB Unmarshaller:

    // Autowiring of the Pool
    @Resource(name = "unmarshallerPool")
    private UnmarshallerPool unmarshallerPool;

    public void myMethod() {
        Unmarshaller u = null;
        try {
            // Borrow an Unmarshaller from the pool
            u = (Unmarshaller) this.unmarshallerPool.borrowObject(MyJAXBClass.class);
            MyJAXBClass myJAXBObject = (MyJAXBClass) u.unmarshal(url);
            // Do whatever
        } catch (Exception e) {
            // Deal with that error
        } finally {
            try {
                // Return the Unmarshaller to the pool
                this.unmarshallerPool.returnObject(MyJAXBClass.class, u);
            } catch (Exception ignore) {
            }
        }
    }

This example is naive as it uses only one Class to create the JAXBContext and uses the same Class instance as the Key for the Keyed Pool. This can be improved by passing an Array of Classes as parameter rather than only one Class.

Hope this can help.

like image 553
Bruno Chauvet Avatar asked Apr 01 '11 05:04

Bruno Chauvet


People also ask

Is JAXB Unmarshaller thread safe?

A: The JAXB Specification currently does not address the thread safety of any of the runtime classes. In the case of the Oracle JAXB RI, the JAXBContext class is thread safe, but the Marshaller , Unmarshaller , and Validator classes are not thread safe.

How do you Unmarshal string JAXB?

To unmarshal an xml string into a JAXB object, you will need to create an Unmarshaller from the JAXBContext, then call the unmarshal() method with a source/reader and the expected root object.

Is JAXB context thread safe?

JAXBContext is thread safe and should only be created once and reused to avoid the cost of initializing the metadata multiple times. Marshaller and Unmarshaller are not thread safe, but are lightweight to create and could be created per operation.

What is JAXB Unmarshal?

The JAXB Unmarshaller interface is responsible for governing the process of deserializing the XML data to Java Objects. The unmarshalling to objects can be done to variety of input sources.


1 Answers

The creation of unmarshallers is intended to be light. I would recommend doing some profiling before developing a pooling strategy.

like image 122
bdoughan Avatar answered Oct 04 '22 17:10

bdoughan