users@jaxb.java.net

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

From: KARR, DAVID (ATTSI) <"KARR,>
Date: Mon, 14 Mar 2011 11:32:13 -0700

> -----Original Message-----
> From: KARR, DAVID (ATTSI)
> Sent: Sunday, March 13, 2011 9:58 PM
> To: users_at_jaxb.java.net
> Subject: Getting NPE in
>
"com.sun.xml.bind.v2.runtime.reflect.TransducedAccessor.get(JAXBContext
> Impl, RuntimeNonElementRef)" marshalling to XML
>
> 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?

I've found a workaround for this. I changed the two annotations in
HashMapEntryType to both be @XmlElement. It's not the structure I
wanted, but I also need it to work. Changing only one of them to
@XmlElement doesn't fix the problem.