2

The code attached below produces sporadic test failures (JUnit), works 80% of the time. I'm using a static Templates object. In the case of failure a different than expected JAXB object is placed into 'result' from the transformer.transform(jaxbSource, result) method call.

I've tried locks and synchronizes sections in vain. Also the Templates object is supposed to be thread safe according to spec. Something weird is happening in the transform.

Error symptom: JUnit test failure - suddenly the wrong object is returned from the transform.

Any ideas?

private <S, T> S transform(final Templates template, final Class resultClass, final T data) throws JAXBException, TransformerException {
    Transformer transformer = template.newTransformer();
    final JAXBSource jaxbSource = new JAXBSource(getCachedJAXBContext(data.getClass()), data);
    final Result result = new JAXBResult(getCachedJAXBContext(resultClass));
    transformer.transform(jaxbSource, result);
    return (S) ((JAXBResult) result).getResult();
}
Dimitre Novatchev
  • 240,661
  • 26
  • 293
  • 431
Theresia Sofia Snow
  • 599
  • 1
  • 5
  • 18
  • 2
    No idea what's causing it. It would be useful to tag it "JAXB", and to describe the symptoms of the "sporadic test failures" rather more clearly, ideally supplying enough data so others can reproduce the problem. – Michael Kay Mar 11 '11 at 11:41
  • Yes, it's pretty much code with XSL style sheets and test code though.. – Theresia Sofia Snow Mar 11 '11 at 13:29
  • 1
    What does `getCachedJAXBContext()` do? Could that be returning the "wrong" content? Try logging/printing `jaxbSource` before the transform to ensure you are transforming what you think you are. – Mads Hansen Mar 11 '11 at 13:51
  • It adds an entry to a ConcurrentHashMap, but the errors were present even before adding that. contextMap.putIfAbsent(clazz, JAXBContext.newInstance(clazz)); – Theresia Sofia Snow Mar 14 '11 at 09:51

1 Answers1

1

Since you have multiple classes mapped to the same root element name, you need to pass the type you wish to unmarshal as a parameter to the unmarshal operation. This will mean transforming to an intermediate representation such as: DOM, byte[], String, etc:

private <S, T> S transform(final Templates template, final Class resultClass, final T data) throws JAXBException, TransformerException {
    Transformer transformer = template.newTransformer();
    final JAXBSource jaxbSource = new JAXBSource(getCachedJAXBContext(data.getClass()), data);
    final Result result = new DOMResult();
    transformer.transform(jaxbSource, result);
    return (S) getCachedJAXBContext(resultClass).createUnmarshaller().unmarshal(new DOMSource(result.getNode()), resultClass).getValue();
}

For more information:

bdoughan
  • 147,609
  • 23
  • 300
  • 400