aoqi@0: /* aoqi@0: * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. Oracle designates this aoqi@0: * particular file as subject to the "Classpath" exception as provided aoqi@0: * by Oracle in the LICENSE file that accompanied this code. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: */ aoqi@0: aoqi@0: package com.sun.xml.internal.bind.v2.model.impl; aoqi@0: aoqi@0: import java.util.AbstractList; aoqi@0: import java.util.Collections; aoqi@0: import java.util.List; aoqi@0: aoqi@0: import javax.xml.bind.annotation.XmlElement; aoqi@0: import javax.xml.bind.annotation.XmlElements; aoqi@0: import javax.xml.bind.annotation.XmlList; aoqi@0: import javax.xml.namespace.QName; aoqi@0: aoqi@0: import com.sun.istack.internal.FinalArrayList; aoqi@0: import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo; aoqi@0: import com.sun.xml.internal.bind.v2.model.core.ID; aoqi@0: import com.sun.xml.internal.bind.v2.model.core.PropertyKind; aoqi@0: import com.sun.xml.internal.bind.v2.model.core.TypeInfo; aoqi@0: import com.sun.xml.internal.bind.v2.model.core.TypeRef; aoqi@0: import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException; aoqi@0: aoqi@0: /** aoqi@0: * Common {@link ElementPropertyInfo} implementation used for both aoqi@0: * Annotation Processing and runtime. aoqi@0: * aoqi@0: * @author Kohsuke Kawaguchi aoqi@0: */ aoqi@0: class ElementPropertyInfoImpl aoqi@0: extends ERPropertyInfoImpl aoqi@0: implements ElementPropertyInfo aoqi@0: { aoqi@0: /** aoqi@0: * Lazily computed. aoqi@0: * @see #getTypes() aoqi@0: */ aoqi@0: private List> types; aoqi@0: aoqi@0: private final List> ref = new AbstractList>() { aoqi@0: public TypeInfo get(int index) { aoqi@0: return getTypes().get(index).getTarget(); aoqi@0: } aoqi@0: aoqi@0: public int size() { aoqi@0: return getTypes().size(); aoqi@0: } aoqi@0: }; aoqi@0: aoqi@0: /** aoqi@0: * Lazily computed. aoqi@0: * @see #isRequired() aoqi@0: */ aoqi@0: private Boolean isRequired; aoqi@0: aoqi@0: /** aoqi@0: * @see #isValueList() aoqi@0: */ aoqi@0: private final boolean isValueList; aoqi@0: aoqi@0: ElementPropertyInfoImpl( aoqi@0: ClassInfoImpl parent, aoqi@0: PropertySeed propertySeed) { aoqi@0: super(parent, propertySeed); aoqi@0: aoqi@0: isValueList = seed.hasAnnotation(XmlList.class); aoqi@0: aoqi@0: } aoqi@0: aoqi@0: public List> getTypes() { aoqi@0: if(types==null) { aoqi@0: types = new FinalArrayList>(); aoqi@0: XmlElement[] ann=null; aoqi@0: aoqi@0: XmlElement xe = seed.readAnnotation(XmlElement.class); aoqi@0: XmlElements xes = seed.readAnnotation(XmlElements.class); aoqi@0: aoqi@0: if(xe!=null && xes!=null) { aoqi@0: parent.builder.reportError(new IllegalAnnotationException( aoqi@0: Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format( aoqi@0: nav().getClassName(parent.getClazz())+'#'+seed.getName(), aoqi@0: xe.annotationType().getName(), xes.annotationType().getName()), aoqi@0: xe, xes )); aoqi@0: } aoqi@0: aoqi@0: isRequired = true; aoqi@0: aoqi@0: if(xe!=null) aoqi@0: ann = new XmlElement[]{xe}; aoqi@0: else aoqi@0: if(xes!=null) aoqi@0: ann = xes.value(); aoqi@0: aoqi@0: if(ann==null) { aoqi@0: // default aoqi@0: TypeT t = getIndividualType(); aoqi@0: if(!nav().isPrimitive(t) || isCollection()) aoqi@0: isRequired = false; aoqi@0: // nillableness defaults to true if it's collection aoqi@0: types.add(createTypeRef(calcXmlName((XmlElement)null),t,isCollection(),null)); aoqi@0: } else { aoqi@0: for( XmlElement item : ann ) { aoqi@0: // TODO: handle defaulting in names. aoqi@0: QName name = calcXmlName(item); aoqi@0: TypeT type = reader().getClassValue(item, "type"); aoqi@0: if (nav().isSameType(type, nav().ref(XmlElement.DEFAULT.class))) aoqi@0: type = getIndividualType(); aoqi@0: if((!nav().isPrimitive(type) || isCollection()) && !item.required()) aoqi@0: isRequired = false; aoqi@0: types.add(createTypeRef(name, type, item.nillable(), getDefaultValue(item.defaultValue()) )); aoqi@0: } aoqi@0: } aoqi@0: types = Collections.unmodifiableList(types); aoqi@0: assert !types.contains(null); aoqi@0: } aoqi@0: return types; aoqi@0: } aoqi@0: aoqi@0: private String getDefaultValue(String value) { aoqi@0: if(value.equals("\u0000")) aoqi@0: return null; aoqi@0: else aoqi@0: return value; aoqi@0: } aoqi@0: aoqi@0: /** aoqi@0: * Used by {@link PropertyInfoImpl} to create new instances of {@link TypeRef} aoqi@0: */ aoqi@0: protected TypeRefImpl createTypeRef(QName name,TypeT type,boolean isNillable,String defaultValue) { aoqi@0: return new TypeRefImpl(this,name,type,isNillable,defaultValue); aoqi@0: } aoqi@0: aoqi@0: public boolean isValueList() { aoqi@0: return isValueList; aoqi@0: } aoqi@0: aoqi@0: public boolean isRequired() { aoqi@0: if(isRequired==null) aoqi@0: getTypes(); // compute the value aoqi@0: return isRequired; aoqi@0: } aoqi@0: aoqi@0: public List> ref() { aoqi@0: return ref; aoqi@0: } aoqi@0: aoqi@0: public final PropertyKind kind() { aoqi@0: return PropertyKind.ELEMENT; aoqi@0: } aoqi@0: aoqi@0: protected void link() { aoqi@0: super.link(); aoqi@0: for (TypeRefImpl ref : getTypes() ) { aoqi@0: ref.link(); aoqi@0: } aoqi@0: aoqi@0: if(isValueList()) { aoqi@0: // ugly test, because IDREF's are represented as text on the wire, aoqi@0: // it's OK to be a value list in that case. aoqi@0: if(id()!= ID.IDREF) { aoqi@0: // check if all the item types are simple types aoqi@0: // this can't be done when we compute types because aoqi@0: // not all TypeInfos are available yet aoqi@0: for (TypeRefImpl ref : types) { aoqi@0: if(!ref.getTarget().isSimpleType()) { aoqi@0: parent.builder.reportError(new IllegalAnnotationException( aoqi@0: Messages.XMLLIST_NEEDS_SIMPLETYPE.format( aoqi@0: nav().getTypeName(ref.getTarget().getType())), this )); aoqi@0: break; aoqi@0: } aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: if(!isCollection()) aoqi@0: parent.builder.reportError(new IllegalAnnotationException( aoqi@0: Messages.XMLLIST_ON_SINGLE_PROPERTY.format(), this aoqi@0: )); aoqi@0: } aoqi@0: } aoqi@0: }