1 /* 2 * Copyright (c) 1997, 2011, 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 26 package com.sun.tools.internal.xjc.model; 27 28 import java.util.Collection; 29 import java.util.Collections; 30 import java.util.HashSet; 31 import java.util.List; 32 import java.util.Set; 33 34 import javax.xml.bind.JAXBElement; 35 import javax.xml.bind.annotation.XmlElement; 36 import javax.xml.namespace.QName; 37 38 import com.sun.codemodel.internal.JPackage; 39 import com.sun.codemodel.internal.JType; 40 import com.sun.istack.internal.Nullable; 41 import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.NOT_REPEATED; 42 import static com.sun.tools.internal.xjc.model.CElementPropertyInfo.CollectionMode.REPEATED_VALUE; 43 import com.sun.tools.internal.xjc.model.nav.NClass; 44 import com.sun.tools.internal.xjc.model.nav.NType; 45 import com.sun.tools.internal.xjc.model.nav.NavigatorImpl; 46 import com.sun.tools.internal.xjc.outline.Aspect; 47 import com.sun.tools.internal.xjc.outline.Outline; 48 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIInlineBinaryData; 49 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIFactoryMethod; 50 import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder; 51 import com.sun.tools.internal.xjc.reader.Ring; 52 import com.sun.xml.internal.bind.v2.model.core.ElementInfo; 53 import com.sun.xml.internal.xsom.XSElementDecl; 54 import com.sun.xml.internal.xsom.XmlString; 55 56 import org.xml.sax.Locator; 57 58 /** 59 * {@link ElementInfo} implementation for the compile-time model. 60 * 61 * <p> 62 * As an NType, it represents the Java representation of this element 63 * (either JAXBElement<T> or Foo). 64 * 65 * @author Kohsuke Kawaguchi 66 */ 67 public final class CElementInfo extends AbstractCElement 68 implements ElementInfo<NType,NClass>, NType, CClassInfoParent { 69 70 private final QName tagName; 71 72 /** 73 * Represents {@code JAXBElement<ContentType>}. 74 */ 75 private NType type; 76 77 /** 78 * If this element produces its own class, the short name of that class. 79 * Otherwise null. 80 */ 81 private String className; 82 83 /** 84 * If this element is global, the element info is considered to be 85 * package-level, and this points to the package in which this element 86 * lives in. 87 * 88 * <p> 89 * For local elements, this points to the parent {@link CClassInfo}. 90 */ 91 public final CClassInfoParent parent; 92 93 private CElementInfo substitutionHead; 94 95 /** 96 * Lazily computed. 97 */ 98 private Set<CElementInfo> substitutionMembers; 99 100 /** 101 * {@link Model} that owns this object. 102 */ 103 private final Model model; 104 105 private CElementPropertyInfo property; 106 107 /** 108 * Custom {@link #getSqueezedName() squeezed name}, if any. 109 */ 110 private /*almost final*/ @Nullable String squeezedName; 111 112 /** 113 * Creates an element in the given parent. 114 * 115 * <p> 116 * When using this construction, {@link #initContentType(TypeUse, XSElementDecl, XmlString)} 117 * must not be invoked. 118 */ CElementInfo(Model model,QName tagName, CClassInfoParent parent, TypeUse contentType, XmlString defaultValue, XSElementDecl source, CCustomizations customizations, Locator location )119 public CElementInfo(Model model,QName tagName, CClassInfoParent parent, TypeUse contentType, XmlString defaultValue, XSElementDecl source, CCustomizations customizations, Locator location ) { 120 super(model,source,location,customizations); 121 this.tagName = tagName; 122 this.model = model; 123 this.parent = parent; 124 if(contentType!=null) 125 initContentType(contentType, source, defaultValue); 126 127 model.add(this); 128 } 129 130 /** 131 * Creates an element with a class in the given parent. 132 * 133 * <p> 134 * When using this construction, the caller must use 135 * {@link #initContentType(TypeUse, XSElementDecl, XmlString)} to fill in the content type 136 * later. 137 * 138 * This is to avoid a circular model construction dependency between buidling a type 139 * inside an element and element itself. To build a content type, you need to have 140 * {@link CElementInfo} for a parent, so we can't take it as a constructor parameter. 141 */ CElementInfo(Model model,QName tagName, CClassInfoParent parent, String className, CCustomizations customizations, Locator location )142 public CElementInfo(Model model,QName tagName, CClassInfoParent parent, String className, CCustomizations customizations, Locator location ) { 143 this(model,tagName,parent,null,null,null,customizations,location); 144 this.className = className; 145 } 146 initContentType(TypeUse contentType, @Nullable XSElementDecl source, XmlString defaultValue)147 public void initContentType(TypeUse contentType, @Nullable XSElementDecl source, XmlString defaultValue) { 148 assert this.property==null; // must not be called twice 149 150 this.property = new CElementPropertyInfo("Value", 151 contentType.isCollection()?REPEATED_VALUE:NOT_REPEATED, 152 contentType.idUse(), 153 contentType.getExpectedMimeType(), 154 source,null,getLocator(),true); 155 this.property.setAdapter(contentType.getAdapterUse()); 156 BIInlineBinaryData.handle(source,property); 157 property.getTypes().add(new CTypeRef(contentType.getInfo(),tagName,CTypeRef.getSimpleTypeName(source), true,defaultValue)); 158 this.type = NavigatorImpl.createParameterizedType( 159 NavigatorImpl.theInstance.ref(JAXBElement.class), 160 getContentInMemoryType() ); 161 162 BIFactoryMethod factoryMethod = Ring.get(BGMBuilder.class).getBindInfo(source).get(BIFactoryMethod.class); 163 if(factoryMethod!=null) { 164 factoryMethod.markAsAcknowledged(); 165 this.squeezedName = factoryMethod.name; 166 } 167 168 } 169 getDefaultValue()170 public final String getDefaultValue() { 171 return getProperty().getTypes().get(0).getDefaultValue(); 172 } 173 _package()174 public final JPackage _package() { 175 return parent.getOwnerPackage(); 176 } 177 getContentType()178 public CNonElement getContentType() { 179 return getProperty().ref().get(0); 180 } 181 getContentInMemoryType()182 public NType getContentInMemoryType() { 183 if(getProperty().getAdapter()==null) { 184 NType itemType = getContentType().getType(); 185 if(!property.isCollection()) 186 return itemType; 187 188 return NavigatorImpl.createParameterizedType(List.class,itemType); 189 } else { 190 return getProperty().getAdapter().customType; 191 } 192 } 193 getProperty()194 public CElementPropertyInfo getProperty() { 195 return property; 196 } 197 getScope()198 public CClassInfo getScope() { 199 if(parent instanceof CClassInfo) 200 return (CClassInfo)parent; 201 return null; 202 } 203 204 /** 205 * @deprecated why are you calling a method that returns this? 206 */ getType()207 public NType getType() { 208 return this; 209 } 210 getElementName()211 public QName getElementName() { 212 return tagName; 213 } 214 toType(Outline o, Aspect aspect)215 public JType toType(Outline o, Aspect aspect) { 216 if(className==null) 217 return type.toType(o,aspect); 218 else 219 return o.getElement(this).implClass; 220 } 221 222 /** 223 * Returns the "squeezed name" of this element. 224 * 225 * @see CClassInfo#getSqueezedName() 226 */ 227 @XmlElement getSqueezedName()228 public String getSqueezedName() { 229 if(squeezedName!=null) return squeezedName; 230 231 StringBuilder b = new StringBuilder(); 232 CClassInfo s = getScope(); 233 if(s!=null) 234 b.append(s.getSqueezedName()); 235 if(className!=null) 236 b.append(className); 237 else 238 b.append( model.getNameConverter().toClassName(tagName.getLocalPart())); 239 return b.toString(); 240 } 241 getSubstitutionHead()242 public CElementInfo getSubstitutionHead() { 243 return substitutionHead; 244 } 245 getSubstitutionMembers()246 public Collection<CElementInfo> getSubstitutionMembers() { 247 if(substitutionMembers==null) 248 return Collections.emptyList(); 249 else 250 return substitutionMembers; 251 } 252 setSubstitutionHead(CElementInfo substitutionHead)253 public void setSubstitutionHead(CElementInfo substitutionHead) { 254 // don't set it twice 255 assert this.substitutionHead==null; 256 assert substitutionHead!=null; 257 this.substitutionHead = substitutionHead; 258 259 if(substitutionHead.substitutionMembers==null) 260 substitutionHead.substitutionMembers = new HashSet<CElementInfo>(); 261 substitutionHead.substitutionMembers.add(this); 262 } 263 isBoxedType()264 public boolean isBoxedType() { 265 return false; 266 } 267 fullName()268 public String fullName() { 269 if(className==null) 270 return type.fullName(); 271 else { 272 String r = parent.fullName(); 273 if(r.length()==0) return className; 274 else return r+'.'+className; 275 } 276 } 277 accept(Visitor<T> visitor)278 public <T> T accept(Visitor<T> visitor) { 279 return visitor.onElement(this); 280 } 281 getOwnerPackage()282 public JPackage getOwnerPackage() { 283 return parent.getOwnerPackage(); 284 } 285 shortName()286 public String shortName() { 287 return className; 288 } 289 290 /** 291 * True if this element has its own class 292 * (as opposed to be represented as an instance of {@link JAXBElement}. 293 */ hasClass()294 public boolean hasClass() { 295 return className!=null; 296 } 297 } 298