5

Here is my conversion code. This is taking long time when we are dealing with large data... Calling the method almost a million times... We could clearly see that it is holding threads for a while.

Please suggest me some ways to improve the performance!

public class GenericObjectXMLConverter<T> {

  private T t = null;
  private static JAXBContext jaxbContext =null;
  public GenericObjectXMLConverter() {

  }
  public GenericObjectXMLConverter(T obj){
    t = obj;
  }

  protected final Logger  log = Logger.getLogger(getClass());

  /**
   * Converts the java Object and into a xml string message type.
   * @param object the object to convert
   * @return String the converted xml message as string
   */
  public String objectToXMLMessage(T object) {
    StringWriter stringWriter = new StringWriter();
    //JAXBContext jaxbContext=null;
    try {
      jaxbContext = JAXBContext.newInstance(object.getClass());
      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
      jaxbMarshaller.marshal(object, stringWriter);
    } catch (JAXBException e) {
      log.warn("JAXBException occured while converting the java object into xml string :"+e.getMessage());
    }
       /*if(log.isDebugEnabled())
         log.debug("xml string after conversion:"+stringWriter.toString());*/
       return stringWriter.toString();
  }

  /**
   * Converts a xml string message into a Java Object
   * @param string the string message to convert
   * @return Object the result as Java Object. If the message parameter is null then
     *  this method will simply return null.
   */
  @SuppressWarnings("unchecked")
  public T xmlToObject(String message) {
    if(message.equals("") || message.equals(" ") || message.length()==0){
      return null;
    }else{
      T object=null;
      try {
        jaxbContext = JAXBContext.newInstance(t.getClass());
        StringReader reader = new StringReader(message);
        Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
        object = (T)jaxbUnmarshaller.unmarshal(reader);
        } catch (JAXBException e) {
        log.warn("JAXBException occured while converting the xml string into a Java Object :"+e.getMessage());
        }
       /* if(log.isDebugEnabled()){
          log.debug("Java object after conversion:"+object.toString());
        }*/
      return object;
    }
  }

}
Lii
  • 11,553
  • 8
  • 64
  • 88
Shak
  • 177
  • 1
  • 3
  • 18
  • You don't need to create a new marshaller/unmarshaller on each method call. Try "caching" these and see if the performance improves. I have the feeling that the marshaller will cache the class metadata when it's serializing or deserializing. – Augusto Sep 04 '13 at 07:04
  • But the object I am passing are different in each time right ? So how it works ? Can you please elaborate how caching can be done .. – Shak Sep 04 '13 at 07:11
  • It will be great if you can provide me some samples Thanks in Advance – Shak Sep 04 '13 at 07:12
  • The `object instance` might be different, but the `class` will probably be the same. I would be really surprised if you have a million different classes in your project :) - http://stackoverflow.com/questions/1215881/the-difference-between-classes-objects-and-instances. – Augusto Sep 04 '13 at 07:13
  • Soory...I mean million objects only – Shak Sep 04 '13 at 07:15
  • Hi, It would be a great help if you can provide me some examples of how the cahing is done in JAXB ... – Shak Sep 04 '13 at 07:18

2 Answers2

22

Performance and JAXB Runtime Classes

  • You should avoid creating the same JAXBContext over and over. JAXBContext is thread safe and should be reused to improve performance.
  • Marshaller/Unmarshaller are not thread safe, but are quick to create. It's not as big a deal to reuse them.
bdoughan
  • 147,609
  • 23
  • 300
  • 400
6

You should create single JAXBContext object per your bean class. Here is my version to maintain singleton object of JAXBContext per bean class.

public class MyJAXBUtil {
    public static final Map<String, JAXBContext> JAXB_MAP = new HashMap<>();
    public static JAXBContext getJAXBContext(Object object) {
        if(JAXB_MAP.get(object.getClass().getCanonicalName()) != null) {
            return JAXB_MAP.get(object.getClass().getCanonicalName());
        }else {
            try {
                JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
                JAXB_MAP.put(object.getClass().getCanonicalName(), jaxbContext);
                return jaxbContext;
            } catch (JAXBException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
}

You can call getJAXBContext method when you need JAXBContext of your bean class and create Marshaller/Unmarshaller locally.

Nitin
  • 2,701
  • 2
  • 30
  • 60