1/* 2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.xml.internal.bind.v2.model.impl; 27 28import java.util.AbstractList; 29import java.util.Collections; 30import java.util.List; 31 32import javax.xml.bind.annotation.XmlElement; 33import javax.xml.bind.annotation.XmlElements; 34import javax.xml.bind.annotation.XmlList; 35import javax.xml.namespace.QName; 36 37import com.sun.istack.internal.FinalArrayList; 38import com.sun.xml.internal.bind.v2.model.core.ElementPropertyInfo; 39import com.sun.xml.internal.bind.v2.model.core.ID; 40import com.sun.xml.internal.bind.v2.model.core.PropertyKind; 41import com.sun.xml.internal.bind.v2.model.core.TypeInfo; 42import com.sun.xml.internal.bind.v2.model.core.TypeRef; 43import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException; 44 45/** 46 * Common {@link ElementPropertyInfo} implementation used for both 47 * Annotation Processing and runtime. 48 * 49 * @author Kohsuke Kawaguchi 50 */ 51class ElementPropertyInfoImpl<TypeT,ClassDeclT,FieldT,MethodT> 52 extends ERPropertyInfoImpl<TypeT,ClassDeclT,FieldT,MethodT> 53 implements ElementPropertyInfo<TypeT,ClassDeclT> 54{ 55 /** 56 * Lazily computed. 57 * @see #getTypes() 58 */ 59 private List<TypeRefImpl<TypeT,ClassDeclT>> types; 60 61 private final List<TypeInfo<TypeT,ClassDeclT>> ref = new AbstractList<TypeInfo<TypeT,ClassDeclT>>() { 62 public TypeInfo<TypeT,ClassDeclT> get(int index) { 63 return getTypes().get(index).getTarget(); 64 } 65 66 public int size() { 67 return getTypes().size(); 68 } 69 }; 70 71 /** 72 * Lazily computed. 73 * @see #isRequired() 74 */ 75 private Boolean isRequired; 76 77 /** 78 * @see #isValueList() 79 */ 80 private final boolean isValueList; 81 82 ElementPropertyInfoImpl( 83 ClassInfoImpl<TypeT,ClassDeclT,FieldT,MethodT> parent, 84 PropertySeed<TypeT,ClassDeclT,FieldT,MethodT> propertySeed) { 85 super(parent, propertySeed); 86 87 isValueList = seed.hasAnnotation(XmlList.class); 88 89 } 90 91 public List<? extends TypeRefImpl<TypeT,ClassDeclT>> getTypes() { 92 if(types==null) { 93 types = new FinalArrayList<TypeRefImpl<TypeT,ClassDeclT>>(); 94 XmlElement[] ann=null; 95 96 XmlElement xe = seed.readAnnotation(XmlElement.class); 97 XmlElements xes = seed.readAnnotation(XmlElements.class); 98 99 if(xe!=null && xes!=null) { 100 parent.builder.reportError(new IllegalAnnotationException( 101 Messages.MUTUALLY_EXCLUSIVE_ANNOTATIONS.format( 102 nav().getClassName(parent.getClazz())+'#'+seed.getName(), 103 xe.annotationType().getName(), xes.annotationType().getName()), 104 xe, xes )); 105 } 106 107 isRequired = true; 108 109 if(xe!=null) 110 ann = new XmlElement[]{xe}; 111 else 112 if(xes!=null) 113 ann = xes.value(); 114 115 if(ann==null) { 116 // default 117 TypeT t = getIndividualType(); 118 if(!nav().isPrimitive(t) || isCollection()) 119 isRequired = false; 120 // nillableness defaults to true if it's collection 121 types.add(createTypeRef(calcXmlName((XmlElement)null),t,isCollection(),null)); 122 } else { 123 for( XmlElement item : ann ) { 124 // TODO: handle defaulting in names. 125 QName name = calcXmlName(item); 126 TypeT type = reader().getClassValue(item, "type"); 127 if (nav().isSameType(type, nav().ref(XmlElement.DEFAULT.class))) 128 type = getIndividualType(); 129 if((!nav().isPrimitive(type) || isCollection()) && !item.required()) 130 isRequired = false; 131 types.add(createTypeRef(name, type, item.nillable(), getDefaultValue(item.defaultValue()) )); 132 } 133 } 134 types = Collections.unmodifiableList(types); 135 assert !types.contains(null); 136 } 137 return types; 138 } 139 140 private String getDefaultValue(String value) { 141 if(value.equals("\u0000")) 142 return null; 143 else 144 return value; 145 } 146 147 /** 148 * Used by {@link PropertyInfoImpl} to create new instances of {@link TypeRef} 149 */ 150 protected TypeRefImpl<TypeT,ClassDeclT> createTypeRef(QName name,TypeT type,boolean isNillable,String defaultValue) { 151 return new TypeRefImpl<TypeT,ClassDeclT>(this,name,type,isNillable,defaultValue); 152 } 153 154 public boolean isValueList() { 155 return isValueList; 156 } 157 158 public boolean isRequired() { 159 if(isRequired==null) 160 getTypes(); // compute the value 161 return isRequired; 162 } 163 164 public List<? extends TypeInfo<TypeT,ClassDeclT>> ref() { 165 return ref; 166 } 167 168 public final PropertyKind kind() { 169 return PropertyKind.ELEMENT; 170 } 171 172 protected void link() { 173 super.link(); 174 for (TypeRefImpl<TypeT, ClassDeclT> ref : getTypes() ) { 175 ref.link(); 176 } 177 178 if(isValueList()) { 179 // ugly test, because IDREF's are represented as text on the wire, 180 // it's OK to be a value list in that case. 181 if(id()!= ID.IDREF) { 182 // check if all the item types are simple types 183 // this can't be done when we compute types because 184 // not all TypeInfos are available yet 185 for (TypeRefImpl<TypeT,ClassDeclT> ref : types) { 186 if(!ref.getTarget().isSimpleType()) { 187 parent.builder.reportError(new IllegalAnnotationException( 188 Messages.XMLLIST_NEEDS_SIMPLETYPE.format( 189 nav().getTypeName(ref.getTarget().getType())), this )); 190 break; 191 } 192 } 193 } 194 195 if(!isCollection()) 196 parent.builder.reportError(new IllegalAnnotationException( 197 Messages.XMLLIST_ON_SINGLE_PROPERTY.format(), this 198 )); 199 } 200 } 201} 202