users@jaxb.java.net

Getting NPE in "com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.get(JAXBContextImpl, RuntimeNonElementRef)" marshalling to XML

From: KARR, DAVID (ATTSI) <"KARR,>
Date: Sun, 13 Mar 2011 21:57:59 -0700

I have an app using the JAX-RS implementation of CXF. I've added JAXB
annotations to the classes I want to render. Up to a certain point, the
objects were rendering fine.

I then added a Map property and discovered I had to define an
XmlAdapter, as JAXB can't render Maps directly. I looked in the javadoc
for XmlAdapter, and I looked at the sample in the Java EE 5 tutorial. I
believe I met all the requirements, although my implementation is
slightly different. I didn't see any reason my HashMapType and
HashMapEntry couldn't be generic, although the Adapter class obviously
has to be type-specific.

After I added these changes, the marshalling process fails with a
NullPointerException. Even worse, it doesn't report a stack trace. I
only see the following output:

org.apache.cxf.jaxrs.impl.WebApplicationExceptionMapper toResponse
WARNING: WebApplicationException has been caught : cause is
java.lang.NullPointerException

I ran my test case in the debugger and had it break on a NPE. I found
that it was throwing the NPE at line 165 in class
"com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor<BeanT>".

That line is in this function (decompiled from class):

/* */ public static <T> TransducedAccessor<T> get(JAXBContextImpl
context, RuntimeNonElementRef ref)
/* */ {
/* 153 */ Transducer xducer =
RuntimeModelBuilder.createTransducer(ref);
/* 154 */ RuntimePropertyInfo prop = ref.getSource();
/* */
/* 156 */ if (prop.isCollection()) {
/* 157 */ return new ListTransducedAccessorImpl(xducer,
prop.getAccessor(),
Lister.create(Navigator.REFLECTION.erasure(prop.getRawType()),
prop.id(), prop.getAdapter()));
/* */ }
/* */
/* 162 */ if (prop.id() == ID.IDREF) {
/* 163 */ return new
IDREFTransducedAccessorImpl(prop.getAccessor());
/* */ }
/* 165 */ if ((xducer.isDefault()) && (!(context.fastBoot))) {
/* 166 */ TransducedAccessor xa =
OptimizedTransducedAccessorFactory.get(prop);
/* 167 */ if (xa != null) return xa;
/* */ }
/* */
/* 170 */ if (xducer.useNamespace()) {
/* 171 */ return new
CompositeContextDependentTransducedAccessorImpl(context, xducer,
prop.getAccessor());
/* */ }
/* 173 */ return new CompositeTransducedAccessorImpl(context,
xducer, prop.getAccessor());
/* */ }

The NPE happens because "xducer" is null.

I googled this class, method, and line number, and I found one person on
StackOverflow who got an NPE on the same line, but his situation seems
to be slightly different.

So, I figure I must have made a mistake in setting up the XmlAdapter.

The following is where I declared the field I'm annotating:

    @XmlElement(name = "myMap")
    @XmlJavaTypeAdapter(HashMapStringStringAdapter.class)
    private HashMap<String, String> myMap;

Here's the adapter class:

public class HashMapStringStringAdapter extends
XmlAdapter<HashMapType<String,String>,HashMap<String,String>> {

    @Override
    public HashMap<String, String> unmarshal(HashMapType<String, String>
value) throws Exception {
        HashMap<String, String> result = new HashMap<String, String>();
        for (HashMapEntryType<String, String> hashMapEntry :
value.getEntries())
            result.put(hashMapEntry.key, hashMapEntry.value);
        return result;
    }

    @Override
    public HashMapType<String, String> marshal(HashMap<String, String>
value) throws Exception {
        HashMapType<String, String> result = new HashMapType<String,
String>();
        for (Map.Entry<String, String> entry : value.entrySet())
            result.put(entry.getKey(), entry.getValue());
        return result;
    }
}

Here's the HashMapType:

public class HashMapType<K,V> {
    private List<HashMapEntryType<K,V>> entries = new
ArrayList<HashMapEntryType<K,V>>();
    public List<HashMapEntryType<K,V>> getEntries() { return entries; }
    public void setEntries(List<HashMapEntryType<K,V>> entries) {
this.entries = entries; }
    public void put(K key, V value) {
        getEntries().add(new HashMapEntryType<K,V>(key, value));
    }
}

And the HashMapEntryType:

public class HashMapEntryType<K,V> {
    @XmlAttribute
    public K key;
    @XmlValue
    public V value;
    public HashMapEntryType() {}
    public HashMapEntryType(K key, V value) {
        this.key = key;
        this.value = value;
    }
}

Anyone have any idea what I might be doing wrong?