src/share/jaxws_classes/com/sun/xml/internal/bind/v2/runtime/property/SingleElementLeafProperty.java

Print this page

        

*** 24,40 **** --- 24,44 ---- */ package com.sun.xml.internal.bind.v2.runtime.property; import java.io.IOException; + import java.lang.reflect.Modifier; + import javax.xml.bind.JAXBElement; import javax.xml.stream.XMLStreamException; import com.sun.xml.internal.bind.api.AccessorException; + import com.sun.xml.internal.bind.v2.model.core.ID; import com.sun.xml.internal.bind.v2.model.core.PropertyKind; import com.sun.xml.internal.bind.v2.model.runtime.RuntimeElementPropertyInfo; import com.sun.xml.internal.bind.v2.model.runtime.RuntimeTypeRef; + import com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl; import com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl; import com.sun.xml.internal.bind.v2.runtime.Name; import com.sun.xml.internal.bind.v2.runtime.XMLSerializer; import com.sun.xml.internal.bind.v2.runtime.reflect.Accessor; import com.sun.xml.internal.bind.v2.runtime.reflect.TransducedAccessor;
*** 59,68 **** --- 63,73 ---- private final boolean nillable; private final Accessor acc; private final String defaultValue; private final TransducedAccessor<BeanT> xacc; private final boolean improvedXsiTypeHandling; + private final boolean idRef; public SingleElementLeafProperty(JAXBContextImpl context, RuntimeElementPropertyInfo prop) { super(context, prop); RuntimeTypeRef ref = prop.getTypes().get(0); tagName = context.nameBuilder.createElementName(ref.getTagName());
*** 73,82 **** --- 78,88 ---- xacc = TransducedAccessor.get(context, ref); assert xacc != null; improvedXsiTypeHandling = context.improvedXsiTypeHandling; + idRef = ref.getSource().id() == ID.IDREF; } public void reset(BeanT o) throws AccessorException { acc.set(o, null); }
*** 98,136 **** } Class valueType = acc.getValueType(); // check for different type than expected. If found, add xsi:type declaration ! if (improvedXsiTypeHandling && !acc.isAdapted() && ! (obj!=null) && ( !obj.getClass().equals(valueType))&& ! (!valueType.isPrimitive() && acc.isValueTypeAbstractable() )) { ! w.startElement(tagName, outerPeer); ! w.childAsXsiType(obj, fieldName, w.grammar.getBeanInfo(valueType), nillable); w.endElement(); - } else { // current type is expected - if (hasValue) { xacc.writeLeafElement(w, tagName, o, fieldName); } else if (nillable) { w.startElement(tagName, null); w.writeXsiNilTrue(); w.endElement(); } } } public void buildChildElementUnmarshallers(UnmarshallerChain chain, QNameMap<ChildLoader> handlers) { Loader l = new LeafPropertyLoader(xacc); if (defaultValue != null) l = new DefaultValueLoaderDecorator(l, defaultValue); if (nillable || chain.context.allNillable) l = new XsiNilLoader.Single(l, acc); // LeafPropertyXsiLoader doesn't work well with nillable elements ! if (improvedXsiTypeHandling && !nillable) l = new LeafPropertyXsiLoader(l, xacc, acc); handlers.put(tagName, new ChildLoader(l, null)); } --- 104,178 ---- } Class valueType = acc.getValueType(); // check for different type than expected. If found, add xsi:type declaration ! if (xsiTypeNeeded(o, w, obj, valueType)) { w.startElement(tagName, outerPeer); ! w.childAsXsiType(obj, fieldName, w.grammar.getBeanInfo(valueType), false); w.endElement(); } else { // current type is expected if (hasValue) { xacc.writeLeafElement(w, tagName, o, fieldName); } else if (nillable) { w.startElement(tagName, null); w.writeXsiNilTrue(); w.endElement(); } } } + /** + * Checks if xsi type needed to be specified + */ + private boolean xsiTypeNeeded(BeanT bean, XMLSerializer w, Object value, Class valueTypeClass) { + if (!improvedXsiTypeHandling) // improved xsi type set + return false; + if (acc.isAdapted()) // accessor is not adapted + return false; + if (value == null) // value is not null + return false; + if (value.getClass().equals(valueTypeClass)) // value represented by different class + return false; + if (idRef) // IDREF + return false; + if (valueTypeClass.isPrimitive()) // is not primitive + return false; + return acc.isValueTypeAbstractable() || isNillableAbstract(bean, w.grammar, value, valueTypeClass); + } + + /** + * Checks if element is nillable and represented by abstract class. + */ + private boolean isNillableAbstract(BeanT bean, JAXBContextImpl context, Object value, Class valueTypeClass) { + if (!nillable) // check if element is nillable + return false; + if (valueTypeClass != Object.class) // required type wasn't recognized + return false; + if (bean.getClass() != JAXBElement.class) // is JAXBElement + return false; + JAXBElement jaxbElement = (JAXBElement) bean; + Class valueClass = value.getClass(); + Class declaredTypeClass = jaxbElement.getDeclaredType(); + if (declaredTypeClass.equals(valueClass)) // JAXBElement<class> is different from unadapted class) + return false; + if (!declaredTypeClass.isAssignableFrom(valueClass)) // and is subclass from it + return false; + if (!Modifier.isAbstract(declaredTypeClass.getModifiers())) // declared class is abstract + return false; + return acc.isAbstractable(declaredTypeClass); // and is not builtin type + } + public void buildChildElementUnmarshallers(UnmarshallerChain chain, QNameMap<ChildLoader> handlers) { Loader l = new LeafPropertyLoader(xacc); if (defaultValue != null) l = new DefaultValueLoaderDecorator(l, defaultValue); if (nillable || chain.context.allNillable) l = new XsiNilLoader.Single(l, acc); // LeafPropertyXsiLoader doesn't work well with nillable elements ! if (improvedXsiTypeHandling) l = new LeafPropertyXsiLoader(l, xacc, acc); handlers.put(tagName, new ChildLoader(l, null)); }