package com.sun.xml.internal.bind.v2.model.impl;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import javax.activation.MimeType;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAttachmentRef;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlID;
import javax.xml.bind.annotation.XmlIDREF;
import javax.xml.bind.annotation.XmlInlineBinaryData;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;
import com.sun.istack.internal.FinalArrayList;
import com.sun.xml.internal.bind.v2.TODO;
import com.sun.xml.internal.bind.v2.model.annotation.AnnotationSource;
import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
import com.sun.xml.internal.bind.v2.model.core.Adapter;
import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
import com.sun.xml.internal.bind.v2.model.core.ElementInfo;
import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo;
import com.sun.xml.internal.bind.v2.model.core.ID;
import com.sun.xml.internal.bind.v2.model.core.NonElement;
import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
import com.sun.xml.internal.bind.v2.model.core.TypeRef;
import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
import com.sun.xml.internal.bind.v2.runtime.Location;
import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapter;
class ElementInfoImpl<T,C,F,M> extends TypeInfoImpl<T,C,F,M> implements ElementInfo<T,C> {
private final QName tagName;
private final NonElement<T,C> contentType;
private final T tOfJAXBElementT;
private final T elementType;
private final ClassInfo<T,C> scope;
private final XmlElementDecl anno;
private ElementInfoImpl<T,C,F,M> substitutionHead;
private FinalArrayList<ElementInfoImpl<T,C,F,M>> substitutionMembers;
private final M method;
private final Adapter<T,C> adapter;
private final boolean isCollection;
private final ID id;
private final PropertyImpl property;
private final MimeType expectedMimeType;
private final boolean inlineBinary;
private final QName schemaType;
protected class PropertyImpl implements
ElementPropertyInfo<T,C>,
TypeRef<T,C>,
AnnotationSource {
public NonElement<T,C> getTarget() {
return contentType;
}
public QName getTagName() {
return tagName;
}
public List<? extends TypeRef<T,C>> getTypes() {
return Collections.singletonList(this);
}
public List<? extends NonElement<T,C>> ref() {
return Collections.singletonList(contentType);
}
public QName getXmlName() {
return tagName;
}
public boolean isCollectionRequired() {
return false;
}
public boolean isCollectionNillable() {
return true;
}
public boolean isNillable() {
return true;
}
public String getDefaultValue() {
String v = anno.defaultValue();
if(v.equals("\u0000"))
return null;
else
return v;
}
public ElementInfoImpl<T,C,F,M> parent() {
return ElementInfoImpl.this;
}
public String getName() {
return "value";
}
public String displayName() {
return "JAXBElement#value";
}
public boolean isCollection() {
return isCollection;
}
public boolean isValueList() {
return isCollection;
}
public boolean isRequired() {
return true;
}
public PropertyKind kind() {
return PropertyKind.ELEMENT;
}
public Adapter<T,C> getAdapter() {
return adapter;
}
public ID id() {
return id;
}
public MimeType getExpectedMimeType() {
return expectedMimeType;
}
public QName getSchemaType() {
return schemaType;
}
public boolean inlineBinaryData() {
return inlineBinary;
}
public PropertyInfo<T,C> getSource() {
return this;
}
public <A extends Annotation> A readAnnotation(Class<A> annotationType) {
return reader().getMethodAnnotation(annotationType,method,ElementInfoImpl.this);
}
public boolean hasAnnotation(Class<? extends Annotation> annotationType) {
return reader().hasMethodAnnotation(annotationType,method);
}
}
public ElementInfoImpl(ModelBuilder<T,C,F,M> builder,
RegistryInfoImpl<T,C,F,M> registry, M m ) throws IllegalAnnotationException {
super(builder,registry);
this.method = m;
anno = reader().getMethodAnnotation( XmlElementDecl.class, m, this );
assert anno!=null;
assert anno instanceof Locatable;
elementType = nav().getReturnType(m);
T baseClass = nav().getBaseClass(elementType,nav().asDecl(JAXBElement.class));
if(baseClass==null)
throw new IllegalAnnotationException(
Messages.XML_ELEMENT_MAPPING_ON_NON_IXMLELEMENT_METHOD.format(nav().getMethodName(m)),
anno );
tagName = parseElementName(anno);
T[] methodParams = nav().getMethodParameters(m);
Adapter<T,C> a = null;
if(methodParams.length>0) {
XmlJavaTypeAdapter adapter = reader().getMethodAnnotation(XmlJavaTypeAdapter.class,m,this);
if(adapter!=null)
a = new Adapter<T,C>(adapter,reader(),nav());
else {
XmlAttachmentRef xsa = reader().getMethodAnnotation(XmlAttachmentRef.class,m,this);
if(xsa!=null) {
TODO.prototype("in Annotation Processing swaRefAdapter isn't avaialble, so this returns null");
a = new Adapter<T,C>(owner.nav.asDecl(SwaRefAdapter.class),owner.nav);
}
}
}
this.adapter = a;
tOfJAXBElementT =
methodParams.length>0 ? methodParams[0]
: nav().getTypeArgument(baseClass,0);
if(adapter==null) {
T list = nav().getBaseClass(tOfJAXBElementT,nav().asDecl(List.class));
if(list==null) {
isCollection = false;
contentType = builder.getTypeInfo(tOfJAXBElementT,this);
} else {
isCollection = true;
contentType = builder.getTypeInfo(nav().getTypeArgument(list,0),this);
}
} else {
contentType = builder.getTypeInfo(this.adapter.defaultType,this);
isCollection = false;
}
T s = reader().getClassValue(anno,"scope");
if(nav().isSameType(s, nav().ref(XmlElementDecl.GLOBAL.class)))
scope = null;
else {
NonElement<T,C> scp = builder.getClassInfo(nav().asDecl(s),this);
if(!(scp instanceof ClassInfo)) {
throw new IllegalAnnotationException(
Messages.SCOPE_IS_NOT_COMPLEXTYPE.format(nav().getTypeName(s)),
anno );
}
scope = (ClassInfo<T,C>)scp;
}
id = calcId();
property = createPropertyImpl();
this.expectedMimeType = Util.calcExpectedMediaType(property,builder);
this.inlineBinary = reader().hasMethodAnnotation(XmlInlineBinaryData.class,method);
this.schemaType = Util.calcSchemaType(reader(),property,registry.registryClass,
getContentInMemoryType(),this);
}
final QName parseElementName(XmlElementDecl e) {
String local = e.name();
String nsUri = e.namespace();
if(nsUri.equals("##default")) {
XmlSchema xs = reader().getPackageAnnotation(XmlSchema.class,
nav().getDeclaringClassForMethod(method),this);
if(xs!=null)
nsUri = xs.namespace();
else {
nsUri = builder.defaultNsUri;
}
}
return new QName(nsUri.intern(),local.intern());
}
protected PropertyImpl createPropertyImpl() {
return new PropertyImpl();
}
public ElementPropertyInfo<T,C> getProperty() {
return property;
}
public NonElement<T,C> getContentType() {
return contentType;
}
public T getContentInMemoryType() {
if(adapter==null) {
return tOfJAXBElementT;
} else {
return adapter.customType;
}
}
public QName getElementName() {
return tagName;
}
public T getType() {
return elementType;
}
public final boolean canBeReferencedByIDREF() {
return false;
}
private ID calcId() {
if(reader().hasMethodAnnotation(XmlID.class,method)) {
return ID.ID;
} else
if(reader().hasMethodAnnotation(XmlIDREF.class,method)) {
return ID.IDREF;
} else {
return ID.NONE;
}
}
public ClassInfo<T, C> getScope() {
return scope;
}
public ElementInfo<T,C> getSubstitutionHead() {
return substitutionHead;
}
public Collection<? extends ElementInfoImpl<T,C,F,M>> getSubstitutionMembers() {
if(substitutionMembers==null)
return Collections.emptyList();
else
return substitutionMembers;
}
void link() {
if(anno.substitutionHeadName().length()!=0) {
QName name = new QName(
anno.substitutionHeadNamespace(), anno.substitutionHeadName() );
substitutionHead = owner.getElementInfo(null,name);
if(substitutionHead==null) {
builder.reportError(
new IllegalAnnotationException(Messages.NON_EXISTENT_ELEMENT_MAPPING.format(
name.getNamespaceURI(),name.getLocalPart()), anno));
} else
substitutionHead.addSubstitutionMember(this);
} else
substitutionHead = null;
super.link();
}
private void addSubstitutionMember(ElementInfoImpl<T,C,F,M> child) {
if(substitutionMembers==null)
substitutionMembers = new FinalArrayList<ElementInfoImpl<T,C,F,M>>();
substitutionMembers.add(child);
}
public Location getLocation() {
return nav().getMethodLocation(method);
}
}