src/share/jaxws_classes/com/sun/xml/internal/bind/v2/model/impl/ModelBuilder.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
ohair@286 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
ohair@286 4 *
ohair@286 5 * This code is free software; you can redistribute it and/or modify it
ohair@286 6 * under the terms of the GNU General Public License version 2 only, as
ohair@286 7 * published by the Free Software Foundation. Oracle designates this
ohair@286 8 * particular file as subject to the "Classpath" exception as provided
ohair@286 9 * by Oracle in the LICENSE file that accompanied this code.
ohair@286 10 *
ohair@286 11 * This code is distributed in the hope that it will be useful, but WITHOUT
ohair@286 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
ohair@286 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
ohair@286 14 * version 2 for more details (a copy is included in the LICENSE file that
ohair@286 15 * accompanied this code).
ohair@286 16 *
ohair@286 17 * You should have received a copy of the GNU General Public License version
ohair@286 18 * 2 along with this work; if not, write to the Free Software Foundation,
ohair@286 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
ohair@286 20 *
ohair@286 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
ohair@286 22 * or visit www.oracle.com if you need additional information or have any
ohair@286 23 * questions.
ohair@286 24 */
ohair@286 25
ohair@286 26 package com.sun.xml.internal.bind.v2.model.impl;
ohair@286 27
ohair@286 28 import java.util.HashMap;
ohair@286 29 import java.util.Map;
ohair@286 30
ohair@286 31 import javax.xml.bind.annotation.XmlAttachmentRef;
ohair@286 32 import javax.xml.bind.annotation.XmlRegistry;
ohair@286 33 import javax.xml.bind.annotation.XmlSchema;
ohair@286 34 import javax.xml.bind.annotation.XmlSeeAlso;
ohair@286 35 import javax.xml.bind.annotation.XmlTransient;
ohair@286 36 import javax.xml.namespace.QName;
ohair@286 37
ohair@286 38 import com.sun.xml.internal.bind.util.Which;
ohair@286 39 import com.sun.xml.internal.bind.v2.model.annotation.AnnotationReader;
ohair@286 40 import com.sun.xml.internal.bind.v2.model.annotation.ClassLocatable;
ohair@286 41 import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
ohair@286 42 import com.sun.xml.internal.bind.v2.model.core.ClassInfo;
ohair@286 43 import com.sun.xml.internal.bind.v2.model.core.ErrorHandler;
ohair@286 44 import com.sun.xml.internal.bind.v2.model.core.LeafInfo;
ohair@286 45 import com.sun.xml.internal.bind.v2.model.core.NonElement;
ohair@286 46 import com.sun.xml.internal.bind.v2.model.core.PropertyInfo;
ohair@286 47 import com.sun.xml.internal.bind.v2.model.core.PropertyKind;
ohair@286 48 import com.sun.xml.internal.bind.v2.model.core.Ref;
ohair@286 49 import com.sun.xml.internal.bind.v2.model.core.RegistryInfo;
ohair@286 50 import com.sun.xml.internal.bind.v2.model.core.TypeInfo;
ohair@286 51 import com.sun.xml.internal.bind.v2.model.core.TypeInfoSet;
ohair@286 52 import com.sun.xml.internal.bind.v2.model.nav.Navigator;
ohair@286 53 import com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationException;
ohair@286 54 import com.sun.xml.internal.bind.WhiteSpaceProcessor;
ohair@286 55
ohair@286 56
ohair@286 57 /**
ohair@286 58 * Builds a {@link TypeInfoSet} (a set of JAXB properties)
ohair@286 59 * by using {@link ElementInfoImpl} and {@link ClassInfoImpl}.
ohair@286 60 * from annotated Java classes.
ohair@286 61 *
ohair@286 62 * <p>
ohair@286 63 * This class uses {@link Navigator} and {@link AnnotationReader} to
ohair@286 64 * work with arbitrary annotation source and arbitrary Java model.
ohair@286 65 * For this purpose this class is parameterized.
ohair@286 66 *
ohair@286 67 * @author Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
ohair@286 68 */
ohair@286 69 public class ModelBuilder<T,C,F,M> {
ohair@286 70
ohair@286 71 /**
ohair@286 72 * {@link TypeInfo}s that are built will go into this set.
ohair@286 73 */
ohair@286 74 final TypeInfoSetImpl<T,C,F,M> typeInfoSet;
ohair@286 75
ohair@286 76 public final AnnotationReader<T,C,F,M> reader;
ohair@286 77
ohair@286 78 public final Navigator<T,C,F,M> nav;
ohair@286 79
ohair@286 80 /**
ohair@286 81 * Used to detect collisions among global type names.
ohair@286 82 */
ohair@286 83 private final Map<QName,TypeInfo> typeNames = new HashMap<QName,TypeInfo>();
ohair@286 84
ohair@286 85 /**
ohair@286 86 * JAXB doesn't want to use namespaces unless we are told to, but WS-I BP
ohair@286 87 * conformace requires JAX-RPC to always use a non-empty namespace URI.
ohair@286 88 * (see http://www.ws-i.org/Profiles/BasicProfile-1.0-2004-04-16.html#WSDLTYPES R2105)
ohair@286 89 *
ohair@286 90 * <p>
ohair@286 91 * To work around this issue, we allow the use of the empty namespaces to be
ohair@286 92 * replaced by a particular designated namespace URI.
ohair@286 93 *
ohair@286 94 * <p>
ohair@286 95 * This field keeps the value of that replacing namespace URI.
ohair@286 96 * When there's no replacement, this field is set to "".
ohair@286 97 */
ohair@286 98 public final String defaultNsUri;
ohair@286 99
ohair@286 100
ohair@286 101 /**
ohair@286 102 * Packages whose registries are already added.
ohair@286 103 */
ohair@286 104 /*package*/ final Map<String,RegistryInfoImpl<T,C,F,M>> registries
ohair@286 105 = new HashMap<String,RegistryInfoImpl<T,C,F,M>>();
ohair@286 106
ohair@286 107 private final Map<C,C> subclassReplacements;
ohair@286 108
ohair@286 109 /**
ohair@286 110 * @see #setErrorHandler
ohair@286 111 */
ohair@286 112 private ErrorHandler errorHandler;
ohair@286 113 private boolean hadError;
ohair@286 114
ohair@286 115 /**
ohair@286 116 * Set to true if the model includes {@link XmlAttachmentRef}. JAX-WS
ohair@286 117 * needs to know this information.
ohair@286 118 */
ohair@286 119 public boolean hasSwaRef;
ohair@286 120
ohair@286 121 private final ErrorHandler proxyErrorHandler = new ErrorHandler() {
ohair@286 122 public void error(IllegalAnnotationException e) {
ohair@286 123 reportError(e);
ohair@286 124 }
ohair@286 125 };
ohair@286 126
ohair@286 127 public ModelBuilder(
ohair@286 128 AnnotationReader<T, C, F, M> reader,
ohair@286 129 Navigator<T, C, F, M> navigator,
ohair@286 130 Map<C, C> subclassReplacements,
ohair@286 131 String defaultNamespaceRemap
ohair@286 132 ) {
ohair@286 133
ohair@286 134 this.reader = reader;
ohair@286 135 this.nav = navigator;
ohair@286 136 this.subclassReplacements = subclassReplacements;
ohair@286 137 if(defaultNamespaceRemap==null)
ohair@286 138 defaultNamespaceRemap = "";
ohair@286 139 this.defaultNsUri = defaultNamespaceRemap;
ohair@286 140 reader.setErrorHandler(proxyErrorHandler);
ohair@286 141 typeInfoSet = createTypeInfoSet();
ohair@286 142 }
ohair@286 143
ohair@286 144 /**
ohair@286 145 * Makes sure that we are running with 2.1 JAXB API,
ohair@286 146 * and report an error if not.
ohair@286 147 */
ohair@286 148 static {
ohair@286 149 try {
ohair@286 150 XmlSchema s = null;
ohair@286 151 s.location();
ohair@286 152 } catch (NullPointerException e) {
ohair@286 153 // as epxected
ohair@286 154 } catch (NoSuchMethodError e) {
ohair@286 155 // this is not a 2.1 API. Where is it being loaded from?
ohair@286 156 Messages res;
ohair@286 157 if (SecureLoader.getClassClassLoader(XmlSchema.class) == null) {
ohair@286 158 res = Messages.INCOMPATIBLE_API_VERSION_MUSTANG;
ohair@286 159 } else {
ohair@286 160 res = Messages.INCOMPATIBLE_API_VERSION;
ohair@286 161 }
ohair@286 162
ohair@286 163 throw new LinkageError( res.format(
ohair@286 164 Which.which(XmlSchema.class),
ohair@286 165 Which.which(ModelBuilder.class)
ohair@286 166 ));
ohair@286 167 }
ohair@286 168 }
ohair@286 169
ohair@286 170 /**
ohair@286 171 * Makes sure that we don't have conflicting 1.0 runtime,
ohair@286 172 * and report an error if we do.
ohair@286 173 */
ohair@286 174 static {
ohair@286 175 try {
ohair@286 176 WhiteSpaceProcessor.isWhiteSpace("xyz");
ohair@286 177 } catch (NoSuchMethodError e) {
ohair@286 178 // we seem to be getting 1.0 runtime
ohair@286 179 throw new LinkageError( Messages.RUNNING_WITH_1_0_RUNTIME.format(
ohair@286 180 Which.which(WhiteSpaceProcessor.class),
ohair@286 181 Which.which(ModelBuilder.class)
ohair@286 182 ));
ohair@286 183 }
ohair@286 184 }
ohair@286 185
ohair@286 186 protected TypeInfoSetImpl<T,C,F,M> createTypeInfoSet() {
ohair@286 187 return new TypeInfoSetImpl<T,C,F,M>(nav,reader,BuiltinLeafInfoImpl.createLeaves(nav));
ohair@286 188 }
ohair@286 189
ohair@286 190 /**
ohair@286 191 * Builds a JAXB {@link ClassInfo} model from a given class declaration
ohair@286 192 * and adds that to this model owner.
ohair@286 193 *
ohair@286 194 * <p>
ohair@286 195 * Return type is either {@link ClassInfo} or {@link LeafInfo} (for types like
ohair@286 196 * {@link String} or {@link Enum}-derived ones)
ohair@286 197 */
ohair@286 198 public NonElement<T,C> getClassInfo( C clazz, Locatable upstream ) {
ohair@286 199 return getClassInfo(clazz,false,upstream);
ohair@286 200 }
ohair@286 201
ohair@286 202 /**
ohair@286 203 * For limited cases where the caller needs to search for a super class.
ohair@286 204 * This is necessary because we don't want {@link #subclassReplacements}
ohair@286 205 * to kick in for the super class search, which will cause infinite recursion.
ohair@286 206 */
ohair@286 207 public NonElement<T,C> getClassInfo( C clazz, boolean searchForSuperClass, Locatable upstream ) {
ohair@286 208 assert clazz!=null;
ohair@286 209 NonElement<T,C> r = typeInfoSet.getClassInfo(clazz);
ohair@286 210 if(r!=null)
ohair@286 211 return r;
ohair@286 212
ohair@286 213 if(nav.isEnum(clazz)) {
ohair@286 214 EnumLeafInfoImpl<T,C,F,M> li = createEnumLeafInfo(clazz,upstream);
ohair@286 215 typeInfoSet.add(li);
ohair@286 216 r = li;
ohair@286 217 addTypeName(r);
ohair@286 218 } else {
ohair@286 219 boolean isReplaced = subclassReplacements.containsKey(clazz);
ohair@286 220 if(isReplaced && !searchForSuperClass) {
ohair@286 221 // handle it as if the replacement was specified
ohair@286 222 r = getClassInfo(subclassReplacements.get(clazz),upstream);
ohair@286 223 } else
ohair@286 224 if(reader.hasClassAnnotation(clazz,XmlTransient.class) || isReplaced) {
ohair@286 225 // handle it as if the base class was specified
ohair@286 226 r = getClassInfo( nav.getSuperClass(clazz), searchForSuperClass,
ohair@286 227 new ClassLocatable<C>(upstream,clazz,nav) );
ohair@286 228 } else {
ohair@286 229 ClassInfoImpl<T,C,F,M> ci = createClassInfo(clazz,upstream);
ohair@286 230 typeInfoSet.add(ci);
ohair@286 231
ohair@286 232 // compute the closure by eagerly expanding references
ohair@286 233 for( PropertyInfo<T,C> p : ci.getProperties() ) {
ohair@286 234 if(p.kind()== PropertyKind.REFERENCE) {
ohair@286 235 // make sure that we have a registry for this package
ohair@286 236 String pkg = nav.getPackageName(ci.getClazz());
ohair@286 237 if(!registries.containsKey(pkg)) {
ohair@286 238 // insert the package's object factory
ohair@286 239 C c = nav.findClass(pkg + ".ObjectFactory",ci.getClazz());
ohair@286 240 if(c!=null)
ohair@286 241 addRegistry(c,(Locatable)p);
ohair@286 242 }
ohair@286 243 }
ohair@286 244
ohair@286 245 for( TypeInfo<T,C> t : p.ref() )
ohair@286 246 ; // just compute a reference should be suffice
ohair@286 247 }
ohair@286 248 ci.getBaseClass(); // same as above.
ohair@286 249
ohair@286 250 r = ci;
ohair@286 251 addTypeName(r);
ohair@286 252 }
ohair@286 253 }
ohair@286 254
ohair@286 255
ohair@286 256 // more reference closure expansion. @XmlSeeAlso
ohair@286 257 XmlSeeAlso sa = reader.getClassAnnotation(XmlSeeAlso.class, clazz, upstream);
ohair@286 258 if(sa!=null) {
ohair@286 259 for( T t : reader.getClassArrayValue(sa,"value") ) {
ohair@286 260 getTypeInfo(t,(Locatable)sa);
ohair@286 261 }
ohair@286 262 }
ohair@286 263
ohair@286 264
ohair@286 265 return r;
ohair@286 266 }
ohair@286 267
ohair@286 268 /**
ohair@286 269 * Checks the uniqueness of the type name.
ohair@286 270 */
ohair@286 271 private void addTypeName(NonElement<T, C> r) {
ohair@286 272 QName t = r.getTypeName();
ohair@286 273 if(t==null) return;
ohair@286 274
ohair@286 275 TypeInfo old = typeNames.put(t,r);
ohair@286 276 if(old!=null) {
ohair@286 277 // collision
ohair@286 278 reportError(new IllegalAnnotationException(
ohair@286 279 Messages.CONFLICTING_XML_TYPE_MAPPING.format(r.getTypeName()),
ohair@286 280 old, r ));
ohair@286 281 }
ohair@286 282 }
ohair@286 283
ohair@286 284 /**
ohair@286 285 * Have the builder recognize the type (if it hasn't done so yet),
ohair@286 286 * and returns a {@link NonElement} that represents it.
ohair@286 287 *
ohair@286 288 * @return
ohair@286 289 * always non-null.
ohair@286 290 */
ohair@286 291 public NonElement<T,C> getTypeInfo(T t,Locatable upstream) {
ohair@286 292 NonElement<T,C> r = typeInfoSet.getTypeInfo(t);
ohair@286 293 if(r!=null) return r;
ohair@286 294
ohair@286 295 if(nav.isArray(t)) { // no need for checking byte[], because above typeInfoset.getTypeInfo() would return non-null
ohair@286 296 ArrayInfoImpl<T,C,F,M> ai =
ohair@286 297 createArrayInfo(upstream, t);
ohair@286 298 addTypeName(ai);
ohair@286 299 typeInfoSet.add(ai);
ohair@286 300 return ai;
ohair@286 301 }
ohair@286 302
ohair@286 303 C c = nav.asDecl(t);
ohair@286 304 assert c!=null : t.toString()+" must be a leaf, but we failed to recognize it.";
ohair@286 305 return getClassInfo(c,upstream);
ohair@286 306 }
ohair@286 307
ohair@286 308 /**
ohair@286 309 * This method is used to add a root reference to a model.
ohair@286 310 */
ohair@286 311 public NonElement<T,C> getTypeInfo(Ref<T,C> ref) {
ohair@286 312 // TODO: handle XmlValueList
ohair@286 313 assert !ref.valueList;
ohair@286 314 C c = nav.asDecl(ref.type);
ohair@286 315 if(c!=null && reader.getClassAnnotation(XmlRegistry.class,c,null/*TODO: is this right?*/)!=null) {
ohair@286 316 if(!registries.containsKey(nav.getPackageName(c)))
ohair@286 317 addRegistry(c,null);
ohair@286 318 return null; // TODO: is this correct?
ohair@286 319 } else
ohair@286 320 return getTypeInfo(ref.type,null);
ohair@286 321 }
ohair@286 322
ohair@286 323
ohair@286 324 protected EnumLeafInfoImpl<T,C,F,M> createEnumLeafInfo(C clazz,Locatable upstream) {
ohair@286 325 return new EnumLeafInfoImpl<T,C,F,M>(this,upstream,clazz,nav.use(clazz));
ohair@286 326 }
ohair@286 327
ohair@286 328 protected ClassInfoImpl<T,C,F,M> createClassInfo(C clazz, Locatable upstream ) {
ohair@286 329 return new ClassInfoImpl<T,C,F,M>(this,upstream,clazz);
ohair@286 330 }
ohair@286 331
ohair@286 332 protected ElementInfoImpl<T,C,F,M> createElementInfo(
ohair@286 333 RegistryInfoImpl<T,C,F,M> registryInfo, M m) throws IllegalAnnotationException {
ohair@286 334 return new ElementInfoImpl<T,C,F,M>(this,registryInfo,m);
ohair@286 335 }
ohair@286 336
ohair@286 337 protected ArrayInfoImpl<T,C,F,M> createArrayInfo(Locatable upstream, T arrayType) {
ohair@286 338 return new ArrayInfoImpl<T, C, F, M>(this,upstream,arrayType);
ohair@286 339 }
ohair@286 340
ohair@286 341
ohair@286 342 /**
ohair@286 343 * Visits a class with {@link XmlRegistry} and records all the element mappings
ohair@286 344 * in it.
ohair@286 345 */
ohair@286 346 public RegistryInfo<T,C> addRegistry(C registryClass, Locatable upstream ) {
ohair@286 347 return new RegistryInfoImpl<T,C,F,M>(this,upstream,registryClass);
ohair@286 348 }
ohair@286 349
ohair@286 350 /**
ohair@286 351 * Gets a {@link RegistryInfo} for the given package.
ohair@286 352 *
ohair@286 353 * @return
ohair@286 354 * null if no registry exists for the package.
ohair@286 355 * unlike other getXXX methods on this class,
ohair@286 356 * this method is side-effect free.
ohair@286 357 */
ohair@286 358 public RegistryInfo<T,C> getRegistry(String packageName) {
ohair@286 359 return registries.get(packageName);
ohair@286 360 }
ohair@286 361
ohair@286 362 private boolean linked;
ohair@286 363
ohair@286 364 /**
ohair@286 365 * Called after all the classes are added to the type set
ohair@286 366 * to "link" them together.
ohair@286 367 *
ohair@286 368 * <p>
ohair@286 369 * Don't expose implementation classes in the signature.
ohair@286 370 *
ohair@286 371 * @return
ohair@286 372 * fully built {@link TypeInfoSet} that represents the model,
ohair@286 373 * or null if there was an error.
ohair@286 374 */
ohair@286 375 public TypeInfoSet<T,C,F,M> link() {
ohair@286 376
ohair@286 377 assert !linked;
ohair@286 378 linked = true;
ohair@286 379
ohair@286 380 for( ElementInfoImpl ei : typeInfoSet.getAllElements() )
ohair@286 381 ei.link();
ohair@286 382
ohair@286 383 for( ClassInfoImpl ci : typeInfoSet.beans().values() )
ohair@286 384 ci.link();
ohair@286 385
ohair@286 386 for( EnumLeafInfoImpl li : typeInfoSet.enums().values() )
ohair@286 387 li.link();
ohair@286 388
ohair@286 389 if(hadError)
ohair@286 390 return null;
ohair@286 391 else
ohair@286 392 return typeInfoSet;
ohair@286 393 }
ohair@286 394
ohair@286 395 //
ohair@286 396 //
ohair@286 397 // error handling
ohair@286 398 //
ohair@286 399 //
ohair@286 400
ohair@286 401 /**
ohair@286 402 * Sets the error handler that receives errors discovered during the model building.
ohair@286 403 *
ohair@286 404 * @param errorHandler
ohair@286 405 * can be null.
ohair@286 406 */
ohair@286 407 public void setErrorHandler(ErrorHandler errorHandler) {
ohair@286 408 this.errorHandler = errorHandler;
ohair@286 409 }
ohair@286 410
ohair@286 411 public final void reportError(IllegalAnnotationException e) {
ohair@286 412 hadError = true;
ohair@286 413 if(errorHandler!=null)
ohair@286 414 errorHandler.error(e);
ohair@286 415 }
ohair@286 416
ohair@286 417 public boolean isReplaced(C sc) {
ohair@286 418 return subclassReplacements.containsKey(sc);
ohair@286 419 }
ohair@286 420 }

mercurial