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));
}