src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/SimpleTypeBuilder.java

Tue, 09 Apr 2013 14:51:13 +0100

author
alanb
date
Tue, 09 Apr 2013 14:51:13 +0100
changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 637
9c07ef4934dd
permissions
-rw-r--r--

8010393: Update JAX-WS RI to 2.2.9-b12941
Reviewed-by: alanb, erikj
Contributed-by: miroslav.kos@oracle.com, martin.grebac@oracle.com

ohair@286 1 /*
ohair@286 2 * Copyright (c) 1997, 2011, 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.tools.internal.xjc.reader.xmlschema;
ohair@286 27
ohair@286 28 import java.io.StringWriter;
ohair@286 29 import java.math.BigInteger;
ohair@286 30 import java.text.ParseException;
ohair@286 31 import java.util.ArrayList;
ohair@286 32 import java.util.Arrays;
ohair@286 33 import java.util.Collections;
ohair@286 34 import java.util.HashMap;
ohair@286 35 import java.util.HashSet;
ohair@286 36 import java.util.List;
ohair@286 37 import java.util.Map;
ohair@286 38 import java.util.Set;
ohair@286 39 import java.util.Stack;
ohair@286 40
ohair@286 41 import javax.activation.MimeTypeParseException;
alanb@368 42 import javax.xml.bind.DatatypeConverter;
ohair@286 43
ohair@286 44 import com.sun.codemodel.internal.JJavaName;
ohair@286 45 import com.sun.codemodel.internal.util.JavadocEscapeWriter;
alanb@368 46 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
ohair@286 47 import com.sun.tools.internal.xjc.ErrorReceiver;
ohair@286 48 import com.sun.tools.internal.xjc.model.CBuiltinLeafInfo;
ohair@286 49 import com.sun.tools.internal.xjc.model.CClassInfo;
ohair@286 50 import com.sun.tools.internal.xjc.model.CClassInfoParent;
ohair@286 51 import com.sun.tools.internal.xjc.model.CClassRef;
ohair@286 52 import com.sun.tools.internal.xjc.model.CEnumConstant;
ohair@286 53 import com.sun.tools.internal.xjc.model.CEnumLeafInfo;
ohair@286 54 import com.sun.tools.internal.xjc.model.CNonElement;
ohair@286 55 import com.sun.tools.internal.xjc.model.Model;
ohair@286 56 import com.sun.tools.internal.xjc.model.TypeUse;
ohair@286 57 import com.sun.tools.internal.xjc.model.TypeUseFactory;
ohair@286 58 import com.sun.tools.internal.xjc.reader.Const;
ohair@286 59 import com.sun.tools.internal.xjc.reader.Ring;
ohair@286 60 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIConversion;
ohair@286 61 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIEnum;
ohair@286 62 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIEnumMember;
ohair@286 63 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIProperty;
ohair@286 64 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
ohair@286 65 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.EnumMemberMode;
ohair@286 66 import com.sun.tools.internal.xjc.util.MimeTypeRange;
alanb@368 67
ohair@286 68 import static com.sun.xml.internal.bind.v2.WellKnownNamespace.XML_MIME_URI;
alanb@368 69
alanb@368 70 import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapterMarker;
ohair@286 71 import com.sun.xml.internal.xsom.XSAttributeDecl;
ohair@286 72 import com.sun.xml.internal.xsom.XSComplexType;
ohair@286 73 import com.sun.xml.internal.xsom.XSComponent;
ohair@286 74 import com.sun.xml.internal.xsom.XSElementDecl;
ohair@286 75 import com.sun.xml.internal.xsom.XSFacet;
ohair@286 76 import com.sun.xml.internal.xsom.XSListSimpleType;
ohair@286 77 import com.sun.xml.internal.xsom.XSRestrictionSimpleType;
ohair@286 78 import com.sun.xml.internal.xsom.XSSimpleType;
ohair@286 79 import com.sun.xml.internal.xsom.XSUnionSimpleType;
ohair@286 80 import com.sun.xml.internal.xsom.XSVariety;
ohair@286 81 import com.sun.xml.internal.xsom.impl.util.SchemaWriter;
ohair@286 82 import com.sun.xml.internal.xsom.visitor.XSSimpleTypeFunction;
ohair@286 83 import com.sun.xml.internal.xsom.visitor.XSVisitor;
ohair@286 84
ohair@286 85 import org.xml.sax.Locator;
ohair@286 86
ohair@286 87 /**
ohair@286 88 * Builds {@link TypeUse} from simple types.
ohair@286 89 *
ohair@286 90 * <p>
ohair@286 91 * This code consists of two main portions. The {@link #compose(XSSimpleType)} method
ohair@286 92 * and {@link #composer} forms an outer cycle, which gradually ascends the type
ohair@286 93 * inheritance chain until it finds the suitable binding. When it does this
ohair@286 94 * {@link #initiatingType} is set to the type which started binding, so that we can refer
ohair@286 95 * to the actual constraint facets and such that are applicable on the type.
ohair@286 96 *
ohair@286 97 * <p>
ohair@286 98 * For each intermediate type in the chain, the {@link #find(XSSimpleType)} method
ohair@286 99 * is used to find the binding on that type, sine the outer loop is doing the ascending,
ohair@286 100 * this method only sees if the current type has some binding available.
ohair@286 101 *
ohair@286 102 * <p>
ohair@286 103 * There is at least one ugly code that you need to aware of
ohair@286 104 * when you are modifying the code. See the documentation
ohair@286 105 * about <a href="package.html#stref_cust">
ohair@286 106 * "simple type customization at the point of reference."</a>
ohair@286 107 *
ohair@286 108 *
ohair@286 109 * @author
ohair@286 110 * Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
ohair@286 111 */
ohair@286 112 public final class SimpleTypeBuilder extends BindingComponent {
ohair@286 113
ohair@286 114 protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
ohair@286 115
ohair@286 116 private final Model model = Ring.get(Model.class);
ohair@286 117
ohair@286 118 /**
ohair@286 119 * The component that is refering to the simple type
ohair@286 120 * which we are building. This is ugly but necessary
ohair@286 121 * to support the customization of simple types at
ohair@286 122 * its point of reference. See my comment at the header
ohair@286 123 * of this class for details.
ohair@286 124 *
ohair@286 125 * UGLY: Implemented as a Stack of XSComponent to fix a bug
ohair@286 126 */
ohair@286 127 public final Stack<XSComponent> refererStack = new Stack<XSComponent>();
ohair@286 128
ohair@286 129 /**
ohair@286 130 * Records what xmime:expectedContentTypes annotations we honored and processed,
ohair@286 131 * so that we can later check if the user had these annotations in the places
ohair@286 132 * where we didn't anticipate them.
ohair@286 133 */
ohair@286 134 private final Set<XSComponent> acknowledgedXmimeContentTypes = new HashSet<XSComponent>();
ohair@286 135
ohair@286 136 /**
ohair@286 137 * The type that was originally passed to this {@link SimpleTypeBuilder#build(XSSimpleType)}.
ohair@286 138 * Never null.
ohair@286 139 */
ohair@286 140 private XSSimpleType initiatingType;
ohair@286 141
ohair@286 142 /** {@link TypeUse}s for the built-in types. Read-only. */
ohair@286 143 public static final Map<String,TypeUse> builtinConversions = new HashMap<String,TypeUse>();
ohair@286 144
ohair@286 145
ohair@286 146 /**
ohair@286 147 * Entry point from outside. Builds a BGM type expression
ohair@286 148 * from a simple type schema component.
ohair@286 149 *
ohair@286 150 * @param type
ohair@286 151 * the simple type to be bound.
ohair@286 152 */
ohair@286 153 public TypeUse build( XSSimpleType type ) {
ohair@286 154 XSSimpleType oldi = initiatingType;
ohair@286 155 this.initiatingType = type;
ohair@286 156
ohair@286 157 TypeUse e = checkRefererCustomization(type);
ohair@286 158 if(e==null)
ohair@286 159 e = compose(type);
ohair@286 160
ohair@286 161 initiatingType = oldi;
ohair@286 162
ohair@286 163 return e;
ohair@286 164 }
ohair@286 165
ohair@286 166 /**
ohair@286 167 * A version of the {@link #build(XSSimpleType)} method
ohair@286 168 * used to bind the definition of a class generated from
ohair@286 169 * the given simple type.
ohair@286 170 */
ohair@286 171 public TypeUse buildDef( XSSimpleType type ) {
ohair@286 172 XSSimpleType oldi = initiatingType;
ohair@286 173 this.initiatingType = type;
ohair@286 174
ohair@286 175 TypeUse e = type.apply(composer);
ohair@286 176
ohair@286 177 initiatingType = oldi;
ohair@286 178
ohair@286 179 return e;
ohair@286 180 }
ohair@286 181
ohair@286 182
ohair@286 183 /**
ohair@286 184 * Returns a javaType customization specified to the referer, if present.
ohair@286 185 * @return can be null.
ohair@286 186 */
ohair@286 187 private BIConversion getRefererCustomization() {
ohair@286 188 BindInfo info = builder.getBindInfo(getReferer());
ohair@286 189 BIProperty prop = info.get(BIProperty.class);
ohair@286 190 if(prop==null) return null;
ohair@286 191 return prop.getConv();
ohair@286 192 }
ohair@286 193
ohair@286 194 public XSComponent getReferer() {
ohair@286 195 return refererStack.peek();
ohair@286 196 }
ohair@286 197
ohair@286 198 /**
ohair@286 199 * Checks if the referer has a conversion customization or not.
ohair@286 200 * If it does, use it to bind this simple type. Otherwise
ohair@286 201 * return null;
ohair@286 202 */
ohair@286 203 private TypeUse checkRefererCustomization( XSSimpleType type ) {
ohair@286 204
ohair@286 205 // assertion check. referer must be set properly
ohair@286 206 // before the build method is called.
ohair@286 207 // since the handling of the simple type point-of-reference
ohair@286 208 // customization is very error prone, it deserves a strict
ohair@286 209 // assertion check.
ohair@286 210 // UGLY CODE WARNING
ohair@286 211 XSComponent top = getReferer();
ohair@286 212
ohair@286 213 if( top instanceof XSElementDecl ) {
ohair@286 214 // if the parent is element type, its content type must be us.
ohair@286 215 XSElementDecl eref = (XSElementDecl)top;
ohair@286 216 assert eref.getType()==type;
ohair@286 217
ohair@286 218 // for elements, you can't use <property>,
ohair@286 219 // so we allow javaType to appear directly.
ohair@286 220 BindInfo info = builder.getBindInfo(top);
ohair@286 221 BIConversion conv = info.get(BIConversion.class);
ohair@286 222 if(conv!=null) {
ohair@286 223 conv.markAsAcknowledged();
ohair@286 224 // the conversion is given.
ohair@286 225 return conv.getTypeUse(type);
ohair@286 226 }
ohair@286 227 detectJavaTypeCustomization();
ohair@286 228 } else
ohair@286 229 if( top instanceof XSAttributeDecl ) {
ohair@286 230 XSAttributeDecl aref = (XSAttributeDecl)top;
ohair@286 231 assert aref.getType()==type;
ohair@286 232 detectJavaTypeCustomization();
ohair@286 233 } else
ohair@286 234 if( top instanceof XSComplexType ) {
ohair@286 235 XSComplexType tref = (XSComplexType)top;
ohair@286 236 assert tref.getBaseType()==type || tref.getContentType()==type;
ohair@286 237 detectJavaTypeCustomization();
ohair@286 238 } else
ohair@286 239 if( top == type ) {
ohair@286 240 // this means the simple type is built by itself and
ohair@286 241 // not because it's referenced by something.
ohair@286 242 } else
ohair@286 243 // unexpected referer type.
ohair@286 244 assert false;
ohair@286 245
ohair@286 246 // now we are certain that the referer is OK.
ohair@286 247 // see if it has a conversion customization.
ohair@286 248 BIConversion conv = getRefererCustomization();
ohair@286 249 if(conv!=null) {
ohair@286 250 conv.markAsAcknowledged();
ohair@286 251 // the conversion is given.
ohair@286 252 return conv.getTypeUse(type);
ohair@286 253 } else
ohair@286 254 // not found
ohair@286 255 return null;
ohair@286 256 }
ohair@286 257
ohair@286 258 /**
ohair@286 259 * Detect "javaType" customizations placed directly on simple types, rather
ohair@286 260 * than being enclosed by "property" and "baseType" customizations (see
ohair@286 261 * sec 6.8.1 of the spec).
ohair@286 262 *
ohair@286 263 * Report an error if any exist.
ohair@286 264 */
ohair@286 265 private void detectJavaTypeCustomization() {
ohair@286 266 BindInfo info = builder.getBindInfo(getReferer());
ohair@286 267 BIConversion conv = info.get(BIConversion.class);
ohair@286 268
ohair@286 269 if( conv != null ) {
ohair@286 270 // ack this conversion to prevent further error messages
ohair@286 271 conv.markAsAcknowledged();
ohair@286 272
ohair@286 273 // report the error
ohair@286 274 getErrorReporter().error( conv.getLocation(),
ohair@286 275 Messages.ERR_UNNESTED_JAVATYPE_CUSTOMIZATION_ON_SIMPLETYPE );
ohair@286 276 }
ohair@286 277 }
ohair@286 278
ohair@286 279 /**
ohair@286 280 * Recursively decend the type inheritance chain to find a binding.
ohair@286 281 */
ohair@286 282 TypeUse compose( XSSimpleType t ) {
ohair@286 283 TypeUse e = find(t);
ohair@286 284 if(e!=null) return e;
ohair@286 285 return t.apply(composer);
ohair@286 286 }
ohair@286 287
ohair@286 288 public final XSSimpleTypeFunction<TypeUse> composer = new XSSimpleTypeFunction<TypeUse>() {
ohair@286 289
ohair@286 290 public TypeUse listSimpleType(XSListSimpleType type) {
ohair@286 291 // bind item type individually and then compose them into a list
ohair@286 292 // facets on the list shouldn't be taken account when binding item types,
ohair@286 293 // so weed to call build(), not compose().
ohair@286 294 XSSimpleType itemType = type.getItemType();
ohair@286 295 refererStack.push(itemType);
ohair@286 296 TypeUse tu = TypeUseFactory.makeCollection(build(type.getItemType()));
ohair@286 297 refererStack.pop();
ohair@286 298 return tu;
ohair@286 299 }
ohair@286 300
ohair@286 301 public TypeUse unionSimpleType(XSUnionSimpleType type) {
ohair@286 302 boolean isCollection = false;
ohair@286 303 for( int i=0; i<type.getMemberSize(); i++ )
ohair@286 304 if(type.getMember(i).getVariety()==XSVariety.LIST || type.getMember(i).getVariety()==XSVariety.UNION) {
ohair@286 305 isCollection = true;
ohair@286 306 break;
ohair@286 307 }
ohair@286 308
ohair@286 309 TypeUse r = CBuiltinLeafInfo.STRING;
ohair@286 310 if(isCollection)
ohair@286 311 r = TypeUseFactory.makeCollection(r);
ohair@286 312 return r;
ohair@286 313 }
ohair@286 314
ohair@286 315 public TypeUse restrictionSimpleType(XSRestrictionSimpleType type) {
ohair@286 316 // just process the base type.
ohair@286 317 return compose(type.getSimpleBaseType());
ohair@286 318 }
ohair@286 319 };
ohair@286 320
ohair@286 321
ohair@286 322 /**
ohair@286 323 * Checks if there's any binding available on the given type.
ohair@286 324 *
ohair@286 325 * @return
ohair@286 326 * null if not (which causes the {@link #compose(XSSimpleType)} method
ohair@286 327 * to do ascending.
ohair@286 328 */
ohair@286 329 private TypeUse find( XSSimpleType type ) {
ohair@286 330 TypeUse r;
ohair@286 331 boolean noAutoEnum = false;
ohair@286 332
ohair@286 333 // check for user specified conversion
ohair@286 334 BindInfo info = builder.getBindInfo(type);
ohair@286 335 BIConversion conv = info.get(BIConversion.class);
ohair@286 336
ohair@286 337 if( conv!=null ) {
ohair@286 338 // a conversion was found
ohair@286 339 conv.markAsAcknowledged();
ohair@286 340 return conv.getTypeUse(type);
ohair@286 341 }
ohair@286 342
ohair@286 343 // look for enum customization, which is another user specified conversion
ohair@286 344 BIEnum en = info.get(BIEnum.class);
ohair@286 345 if( en!=null ) {
ohair@286 346 en.markAsAcknowledged();
ohair@286 347
ohair@286 348 if(!en.isMapped()) {
ohair@286 349 noAutoEnum = true;
ohair@286 350 } else {
ohair@286 351 // if an enum customization is specified, make sure
ohair@286 352 // the type is OK
ohair@286 353 if( !canBeMappedToTypeSafeEnum(type) ) {
ohair@286 354 getErrorReporter().error( en.getLocation(),
ohair@286 355 Messages.ERR_CANNOT_BE_TYPE_SAFE_ENUM );
ohair@286 356 getErrorReporter().error( type.getLocator(),
ohair@286 357 Messages.ERR_CANNOT_BE_TYPE_SAFE_ENUM_LOCATION );
ohair@286 358 // recover by ignoring this customization
ohair@286 359 return null;
ohair@286 360 }
ohair@286 361
ohair@286 362 // reference?
ohair@286 363 if(en.ref!=null) {
ohair@286 364 if(!JJavaName.isFullyQualifiedClassName(en.ref)) {
ohair@286 365 Ring.get(ErrorReceiver.class).error( en.getLocation(),
ohair@286 366 Messages.format(Messages.ERR_INCORRECT_CLASS_NAME, en.ref) );
ohair@286 367 // recover by ignoring @ref
ohair@286 368 return null;
ohair@286 369 }
ohair@286 370
ohair@286 371 return new CClassRef(model, type, en, info.toCustomizationList() );
ohair@286 372 }
ohair@286 373
ohair@286 374 // list and union cannot be mapped to a type-safe enum,
ohair@286 375 // so in this stage we can safely cast it to XSRestrictionSimpleType
ohair@286 376 return bindToTypeSafeEnum( (XSRestrictionSimpleType)type,
ohair@286 377 en.className, en.javadoc, en.members,
ohair@286 378 getEnumMemberMode().getModeWithEnum(),
ohair@286 379 en.getLocation() );
ohair@286 380 }
ohair@286 381 }
ohair@286 382
ohair@286 383
ohair@286 384 // if the type is built in, look for the default binding
ohair@286 385 if(type.getTargetNamespace().equals(WellKnownNamespace.XML_SCHEMA)) {
ohair@286 386 String name = type.getName();
ohair@286 387 if(name!=null) {
ohair@286 388 r = lookupBuiltin(name);
ohair@286 389 if(r!=null)
ohair@286 390 return r;
ohair@286 391 }
ohair@286 392 }
ohair@286 393
ohair@286 394 // also check for swaRef
ohair@286 395 if(type.getTargetNamespace().equals(WellKnownNamespace.SWA_URI)) {
ohair@286 396 String name = type.getName();
ohair@286 397 if(name!=null && name.equals("swaRef"))
alanb@368 398 return CBuiltinLeafInfo.STRING.makeAdapted(SwaRefAdapterMarker.class,false);
ohair@286 399 }
ohair@286 400
ohair@286 401
ohair@286 402 // see if this type should be mapped to a type-safe enumeration by default.
ohair@286 403 // if so, built a EnumXDucer from it and return it.
ohair@286 404 if(type.isRestriction() && !noAutoEnum) {
ohair@286 405 XSRestrictionSimpleType rst = type.asRestriction();
ohair@286 406 if(shouldBeMappedToTypeSafeEnumByDefault(rst)) {
ohair@286 407 r = bindToTypeSafeEnum(rst,null,null, Collections.<String, BIEnumMember>emptyMap(),
ohair@286 408 getEnumMemberMode(),null);
ohair@286 409 if(r!=null)
ohair@286 410 return r;
ohair@286 411 }
ohair@286 412 }
ohair@286 413
ohair@286 414 return (CNonElement)getClassSelector()._bindToClass(type,null,false);
ohair@286 415 }
ohair@286 416
ohair@286 417 private static Set<XSRestrictionSimpleType> reportedEnumMemberSizeWarnings;
ohair@286 418
ohair@286 419 /**
ohair@286 420 * Returns true if a type-safe enum should be created from
ohair@286 421 * the given simple type by default without an explicit &lt;jaxb:enum> customization.
ohair@286 422 */
ohair@286 423 private boolean shouldBeMappedToTypeSafeEnumByDefault( XSRestrictionSimpleType type ) {
ohair@286 424
ohair@286 425 // if not, there will be a problem wrt the class name of this type safe enum type.
ohair@286 426 if( type.isLocal() ) return false;
ohair@286 427
ohair@286 428 // if redefined, we should map the new definition, not the old one.
ohair@286 429 if( type.getRedefinedBy()!=null ) return false;
ohair@286 430
ohair@286 431 List<XSFacet> facets = type.getDeclaredFacets(XSFacet.FACET_ENUMERATION);
ohair@286 432 if( facets.isEmpty() )
ohair@286 433 // if the type itself doesn't have the enumeration facet,
ohair@286 434 // it won't be mapped to a type-safe enum.
ohair@286 435 return false;
ohair@286 436
ohair@286 437 if(facets.size() > builder.getGlobalBinding().getDefaultEnumMemberSizeCap()) {
ohair@286 438 // if there are too many facets, it's not very useful
ohair@286 439 // produce warning when simple type is not mapped to enum
ohair@286 440 // see issue https://jaxb.dev.java.net/issues/show_bug.cgi?id=711
ohair@286 441
ohair@286 442 if(reportedEnumMemberSizeWarnings == null)
ohair@286 443 reportedEnumMemberSizeWarnings = new HashSet<XSRestrictionSimpleType>();
ohair@286 444
ohair@286 445 if(!reportedEnumMemberSizeWarnings.contains(type)) {
ohair@286 446 getErrorReporter().warning(type.getLocator(), Messages.WARN_ENUM_MEMBER_SIZE_CAP,
ohair@286 447 type.getName(), facets.size(), builder.getGlobalBinding().getDefaultEnumMemberSizeCap());
ohair@286 448
ohair@286 449 reportedEnumMemberSizeWarnings.add(type);
ohair@286 450 }
ohair@286 451
ohair@286 452 return false;
ohair@286 453 }
ohair@286 454
ohair@286 455 if( !canBeMappedToTypeSafeEnum(type) )
ohair@286 456 // we simply can't map this to an enumeration
ohair@286 457 return false;
ohair@286 458
ohair@286 459 // check for collisions among constant names. if a collision will happen,
ohair@286 460 // don't try to bind it to an enum.
ohair@286 461
ohair@286 462 // return true only when this type is derived from one of the "enum base type".
ohair@286 463 for( XSSimpleType t = type; t!=null; t=t.getSimpleBaseType() )
ohair@286 464 if( t.isGlobal() && builder.getGlobalBinding().canBeMappedToTypeSafeEnum(t) )
ohair@286 465 return true;
ohair@286 466
ohair@286 467 return false;
ohair@286 468 }
ohair@286 469
ohair@286 470
ohair@286 471 private static final Set<String> builtinTypeSafeEnumCapableTypes;
ohair@286 472
ohair@286 473 static {
ohair@286 474 Set<String> s = new HashSet<String>();
ohair@286 475
ohair@286 476 // see a bullet of 6.5.1 of the spec.
ohair@286 477 String[] typeNames = new String[] {
ohair@286 478 "string", "boolean", "float", "decimal", "double", "anyURI"
ohair@286 479 };
ohair@286 480 s.addAll(Arrays.asList(typeNames));
ohair@286 481
ohair@286 482 builtinTypeSafeEnumCapableTypes = Collections.unmodifiableSet(s);
ohair@286 483 }
ohair@286 484
ohair@286 485
ohair@286 486 /**
ohair@286 487 * Returns true if the given simple type can be mapped to a
ohair@286 488 * type-safe enum class.
ohair@286 489 *
ohair@286 490 * <p>
ohair@286 491 * JAXB spec places a restrictrion as to what type can be
ohair@286 492 * mapped to a type-safe enum. This method enforces this
ohair@286 493 * constraint.
ohair@286 494 */
ohair@286 495 public static boolean canBeMappedToTypeSafeEnum( XSSimpleType type ) {
ohair@286 496 do {
ohair@286 497 if( WellKnownNamespace.XML_SCHEMA.equals(type.getTargetNamespace()) ) {
ohair@286 498 // type must be derived from one of these types
ohair@286 499 String localName = type.getName();
ohair@286 500 if( localName!=null ) {
ohair@286 501 if( localName.equals("anySimpleType") )
ohair@286 502 return false; // catch all case
ohair@286 503 if( localName.equals("ID") || localName.equals("IDREF") )
ohair@286 504 return false; // not ID/IDREF
ohair@286 505
ohair@286 506 // other allowed list
ohair@286 507 if( builtinTypeSafeEnumCapableTypes.contains(localName) )
ohair@286 508 return true;
ohair@286 509 }
ohair@286 510 }
ohair@286 511
ohair@286 512 type = type.getSimpleBaseType();
ohair@286 513 } while( type!=null );
ohair@286 514
ohair@286 515 return false;
ohair@286 516 }
ohair@286 517
ohair@286 518
ohair@286 519
ohair@286 520 /**
ohair@286 521 * Builds a type-safe enum conversion from a simple type
ohair@286 522 * with enumeration facets.
ohair@286 523 *
ohair@286 524 * @param className
ohair@286 525 * The class name of the type-safe enum. Or null to
ohair@286 526 * create a default name.
ohair@286 527 * @param javadoc
ohair@286 528 * Additional javadoc that will be added at the beginning of the
ohair@286 529 * class, or null if none is necessary.
ohair@286 530 * @param members
ohair@286 531 * A map from enumeration values (as String) to BIEnumMember objects.
ohair@286 532 * if some of the value names need to be overrided.
ohair@286 533 * Cannot be null, but the map may not contain entries
ohair@286 534 * for all enumeration values.
ohair@286 535 * @param loc
ohair@286 536 * The source location where the above customizations are
ohair@286 537 * specified, or null if none is available.
ohair@286 538 */
ohair@286 539 private TypeUse bindToTypeSafeEnum( XSRestrictionSimpleType type,
ohair@286 540 String className, String javadoc, Map<String,BIEnumMember> members,
ohair@286 541 EnumMemberMode mode, Locator loc ) {
ohair@286 542
ohair@286 543 if( loc==null ) // use the location of the simple type as the default
ohair@286 544 loc = type.getLocator();
ohair@286 545
ohair@286 546 if( className==null ) {
ohair@286 547 // infer the class name. For this to be possible,
ohair@286 548 // the simple type must be a global one.
ohair@286 549 if( !type.isGlobal() ) {
ohair@286 550 getErrorReporter().error( loc, Messages.ERR_NO_ENUM_NAME_AVAILABLE );
ohair@286 551 // recover by returning a meaningless conversion
ohair@286 552 return CBuiltinLeafInfo.STRING;
ohair@286 553 }
ohair@286 554 className = type.getName();
ohair@286 555 }
ohair@286 556
ohair@286 557 // we apply name conversion in any case
ohair@286 558 className = builder.deriveName(className,type);
ohair@286 559
ohair@286 560 {// compute Javadoc
ohair@286 561 StringWriter out = new StringWriter();
ohair@286 562 SchemaWriter sw = new SchemaWriter(new JavadocEscapeWriter(out));
ohair@286 563 type.visit((XSVisitor)sw);
ohair@286 564
ohair@286 565 if(javadoc!=null) javadoc += "\n\n";
ohair@286 566 else javadoc = "";
ohair@286 567
ohair@286 568 javadoc += Messages.format( Messages.JAVADOC_HEADING, type.getName() )
ohair@286 569 +"\n<p>\n<pre>\n"+out.getBuffer()+"</pre>";
ohair@286 570
ohair@286 571 }
ohair@286 572
ohair@286 573 // build base type
ohair@286 574 refererStack.push(type.getSimpleBaseType());
ohair@286 575 TypeUse use = build(type.getSimpleBaseType());
ohair@286 576 refererStack.pop();
ohair@286 577
ohair@286 578 if(use.isCollection())
ohair@286 579 return null; // can't bind a list to enum constant
ohair@286 580
ohair@286 581 CNonElement baseDt = use.getInfo(); // for now just ignore that case
ohair@286 582
ohair@286 583 if(baseDt instanceof CClassInfo)
ohair@286 584 return null; // can't bind to an enum if the base is a class, since we don't have the value constrctor
ohair@286 585
ohair@286 586 // if the member names collide, re-generate numbered constant names.
ohair@286 587 XSFacet[] errorRef = new XSFacet[1];
ohair@286 588 List<CEnumConstant> memberList = buildCEnumConstants(type, false, members, errorRef);
ohair@286 589 if(memberList==null || checkMemberNameCollision(memberList)!=null) {
ohair@286 590 switch(mode) {
ohair@286 591 case SKIP:
ohair@286 592 // abort
ohair@286 593 return null;
ohair@286 594 case ERROR:
ohair@286 595 // error
ohair@286 596 if(memberList==null) {
ohair@286 597 getErrorReporter().error( errorRef[0].getLocator(),
ohair@286 598 Messages.ERR_CANNOT_GENERATE_ENUM_NAME,
ohair@286 599 errorRef[0].getValue() );
ohair@286 600 } else {
ohair@286 601 CEnumConstant[] collision = checkMemberNameCollision(memberList);
ohair@286 602 getErrorReporter().error( collision[0].getLocator(),
ohair@286 603 Messages.ERR_ENUM_MEMBER_NAME_COLLISION,
ohair@286 604 collision[0].getName() );
ohair@286 605 getErrorReporter().error( collision[1].getLocator(),
ohair@286 606 Messages.ERR_ENUM_MEMBER_NAME_COLLISION_RELATED );
ohair@286 607 }
ohair@286 608 return null; // recover from error
ohair@286 609 case GENERATE:
ohair@286 610 // generate
ohair@286 611 memberList = buildCEnumConstants(type,true,members,null);
ohair@286 612 break;
ohair@286 613 }
ohair@286 614 }
ohair@286 615 if(memberList.isEmpty()) {
ohair@286 616 getErrorReporter().error( loc, Messages.ERR_NO_ENUM_FACET );
ohair@286 617 return null;
ohair@286 618 }
ohair@286 619
ohair@286 620 // use the name of the simple type as the name of the class.
ohair@286 621 CClassInfoParent scope;
ohair@286 622 if(type.isGlobal())
ohair@286 623 scope = new CClassInfoParent.Package(getClassSelector().getPackage(type.getTargetNamespace()));
ohair@286 624 else
ohair@286 625 scope = getClassSelector().getClassScope();
ohair@286 626 CEnumLeafInfo xducer = new CEnumLeafInfo( model, BGMBuilder.getName(type), scope,
ohair@286 627 className, baseDt, memberList, type,
ohair@286 628 builder.getBindInfo(type).toCustomizationList(), loc );
ohair@286 629 xducer.javadoc = javadoc;
ohair@286 630
ohair@286 631 BIConversion conv = new BIConversion.Static( type.getLocator(),xducer);
ohair@286 632 conv.markAsAcknowledged();
ohair@286 633
ohair@286 634 // attach this new conversion object to this simple type
ohair@286 635 // so that successive look up will use the same object.
ohair@286 636 builder.getOrCreateBindInfo(type).addDecl(conv);
ohair@286 637
ohair@286 638 return conv.getTypeUse(type);
ohair@286 639 }
ohair@286 640
ohair@286 641 /**
ohair@286 642 *
ohair@286 643 * @param errorRef
ohair@286 644 * if constant names couldn't be generated, return a reference to that enum facet.
ohair@286 645 * @return
ohair@286 646 * null if unable to generate names for some of the constants.
ohair@286 647 */
ohair@286 648 private List<CEnumConstant> buildCEnumConstants(XSRestrictionSimpleType type, boolean needsToGenerateMemberName, Map<String, BIEnumMember> members, XSFacet[] errorRef) {
ohair@286 649 List<CEnumConstant> memberList = new ArrayList<CEnumConstant>();
ohair@286 650 int idx=1;
ohair@286 651 Set<String> enums = new HashSet<String>(); // to avoid duplicates. See issue #366
ohair@286 652
ohair@286 653 for( XSFacet facet : type.getDeclaredFacets(XSFacet.FACET_ENUMERATION)) {
ohair@286 654 String name=null;
ohair@286 655 String mdoc=builder.getBindInfo(facet).getDocumentation();
ohair@286 656
ohair@286 657 if(!enums.add(facet.getValue().value))
ohair@286 658 continue; // ignore the 2nd occasion
ohair@286 659
ohair@286 660 if( needsToGenerateMemberName ) {
ohair@286 661 // generate names for all member names.
ohair@286 662 // this will even override names specified by the user. that's crazy.
ohair@286 663 name = "VALUE_"+(idx++);
ohair@286 664 } else {
ohair@286 665 String facetValue = facet.getValue().value;
ohair@286 666 BIEnumMember mem = members.get(facetValue);
ohair@286 667 if( mem==null )
ohair@286 668 // look at the one attached to the facet object
ohair@286 669 mem = builder.getBindInfo(facet).get(BIEnumMember.class);
ohair@286 670
ohair@286 671 if (mem!=null) {
ohair@286 672 name = mem.name;
alanb@368 673 if (mdoc == null) {
ohair@286 674 mdoc = mem.javadoc;
ohair@286 675 }
ohair@286 676 }
ohair@286 677
ohair@286 678 if(name==null) {
ohair@286 679 StringBuilder sb = new StringBuilder();
ohair@286 680 for( int i=0; i<facetValue.length(); i++) {
ohair@286 681 char ch = facetValue.charAt(i);
ohair@286 682 if(Character.isJavaIdentifierPart(ch))
ohair@286 683 sb.append(ch);
ohair@286 684 else
ohair@286 685 sb.append('_');
ohair@286 686 }
ohair@286 687 name = model.getNameConverter().toConstantName(sb.toString());
ohair@286 688 }
ohair@286 689 }
ohair@286 690
ohair@286 691 if(!JJavaName.isJavaIdentifier(name)) {
ohair@286 692 if(errorRef!=null) errorRef[0] = facet;
ohair@286 693 return null; // unable to generate a name
ohair@286 694 }
ohair@286 695
ohair@286 696 memberList.add(new CEnumConstant(name,mdoc,facet.getValue().value,facet,builder.getBindInfo(facet).toCustomizationList(),facet.getLocator()));
ohair@286 697 }
ohair@286 698 return memberList;
ohair@286 699 }
ohair@286 700
ohair@286 701 /**
ohair@286 702 * Returns non-null if {@link CEnumConstant}s have name collisions among them.
ohair@286 703 *
ohair@286 704 * @return
ohair@286 705 * if there's a collision, return two {@link CEnumConstant}s that collided.
ohair@286 706 * otherwise return null.
ohair@286 707 */
ohair@286 708 private CEnumConstant[] checkMemberNameCollision( List<CEnumConstant> memberList ) {
ohair@286 709 Map<String,CEnumConstant> names = new HashMap<String,CEnumConstant>();
ohair@286 710 for (CEnumConstant c : memberList) {
ohair@286 711 CEnumConstant old = names.put(c.getName(),c);
ohair@286 712 if(old!=null)
ohair@286 713 // collision detected
ohair@286 714 return new CEnumConstant[]{old,c};
ohair@286 715 }
ohair@286 716 return null;
ohair@286 717 }
ohair@286 718
ohair@286 719
ohair@286 720
ohair@286 721 private EnumMemberMode getEnumMemberMode() {
ohair@286 722 return builder.getGlobalBinding().getEnumMemberMode();
ohair@286 723 }
ohair@286 724
ohair@286 725 private TypeUse lookupBuiltin( String typeLocalName ) {
ohair@286 726 if(typeLocalName.equals("integer") || typeLocalName.equals("long")) {
ohair@286 727 /*
ohair@286 728 attempt an optimization so that we can
ohair@286 729 improve the binding for types like this:
ohair@286 730
ohair@286 731 <simpleType>
ohair@286 732 <restriciton baseType="integer">
ohair@286 733 <maxInclusive value="100" />
ohair@286 734 </
ohair@286 735 </
ohair@286 736
ohair@286 737 ... to int, not BigInteger.
ohair@286 738 */
ohair@286 739
ohair@286 740 BigInteger xe = readFacet(XSFacet.FACET_MAXEXCLUSIVE,-1);
ohair@286 741 BigInteger xi = readFacet(XSFacet.FACET_MAXINCLUSIVE,0);
ohair@286 742 BigInteger max = min(xe,xi); // most restrictive one takes precedence
ohair@286 743
ohair@286 744 if(max!=null) {
ohair@286 745 BigInteger ne = readFacet(XSFacet.FACET_MINEXCLUSIVE,+1);
ohair@286 746 BigInteger ni = readFacet(XSFacet.FACET_MININCLUSIVE,0);
ohair@286 747 BigInteger min = max(ne,ni);
ohair@286 748
ohair@286 749 if(min!=null) {
ohair@286 750 if(min.compareTo(INT_MIN )>=0 && max.compareTo(INT_MAX )<=0)
ohair@286 751 typeLocalName = "int";
ohair@286 752 else
ohair@286 753 if(min.compareTo(LONG_MIN)>=0 && max.compareTo(LONG_MAX)<=0)
ohair@286 754 typeLocalName = "long";
ohair@286 755 }
ohair@286 756 }
ohair@286 757 } else
ohair@286 758 if(typeLocalName.equals("boolean") && isRestrictedTo0And1()) {
ohair@286 759 // this is seen in the SOAP schema and too common to ignore
ohair@286 760 return CBuiltinLeafInfo.BOOLEAN_ZERO_OR_ONE;
ohair@286 761 } else
ohair@286 762 if(typeLocalName.equals("base64Binary")) {
ohair@286 763 return lookupBinaryTypeBinding();
ohair@286 764 } else
ohair@286 765 if(typeLocalName.equals("anySimpleType")) {
ohair@286 766 if(getReferer() instanceof XSAttributeDecl || getReferer() instanceof XSSimpleType)
ohair@286 767 return CBuiltinLeafInfo.STRING;
ohair@286 768 else
ohair@286 769 return CBuiltinLeafInfo.ANYTYPE;
ohair@286 770 }
ohair@286 771 return builtinConversions.get(typeLocalName);
ohair@286 772 }
ohair@286 773
ohair@286 774 /**
ohair@286 775 * Decides the way xs:base64Binary binds.
ohair@286 776 *
ohair@286 777 * This method checks the expected media type.
ohair@286 778 */
ohair@286 779 private TypeUse lookupBinaryTypeBinding() {
ohair@286 780 XSComponent referer = getReferer();
ohair@286 781 String emt = referer.getForeignAttribute(XML_MIME_URI, Const.EXPECTED_CONTENT_TYPES);
ohair@286 782 if(emt!=null) {
ohair@286 783 acknowledgedXmimeContentTypes.add(referer);
ohair@286 784 try {
ohair@286 785 // see http://www.xml.com/lpt/a/2004/07/21/dive.html
ohair@286 786 List<MimeTypeRange> types = MimeTypeRange.parseRanges(emt);
ohair@286 787 MimeTypeRange mt = MimeTypeRange.merge(types);
ohair@286 788
ohair@286 789 // see spec table I-1 in appendix I section 2.1.1 for bindings
ohair@286 790 if(mt.majorType.equalsIgnoreCase("image"))
ohair@286 791 return CBuiltinLeafInfo.IMAGE.makeMimeTyped(mt.toMimeType());
ohair@286 792
ohair@286 793 if(( mt.majorType.equalsIgnoreCase("application") || mt.majorType.equalsIgnoreCase("text"))
ohair@286 794 && isXml(mt.subType))
ohair@286 795 return CBuiltinLeafInfo.XML_SOURCE.makeMimeTyped(mt.toMimeType());
ohair@286 796
ohair@286 797 if((mt.majorType.equalsIgnoreCase("text") && (mt.subType.equalsIgnoreCase("plain")) )) {
ohair@286 798 return CBuiltinLeafInfo.STRING.makeMimeTyped(mt.toMimeType());
ohair@286 799 }
ohair@286 800
ohair@286 801 return CBuiltinLeafInfo.DATA_HANDLER.makeMimeTyped(mt.toMimeType());
ohair@286 802 } catch (ParseException e) {
ohair@286 803 getErrorReporter().error( referer.getLocator(),
ohair@286 804 Messages.format(Messages.ERR_ILLEGAL_EXPECTED_MIME_TYPE,emt, e.getMessage()) );
ohair@286 805 // recover by using the default
ohair@286 806 } catch (MimeTypeParseException e) {
ohair@286 807 getErrorReporter().error( referer.getLocator(),
ohair@286 808 Messages.format(Messages.ERR_ILLEGAL_EXPECTED_MIME_TYPE,emt, e.getMessage()) );
ohair@286 809 }
ohair@286 810 }
ohair@286 811 // default
ohair@286 812 return CBuiltinLeafInfo.BASE64_BYTE_ARRAY;
ohair@286 813 }
ohair@286 814
ohair@286 815 public boolean isAcknowledgedXmimeContentTypes(XSComponent c) {
ohair@286 816 return acknowledgedXmimeContentTypes.contains(c);
ohair@286 817 }
ohair@286 818
ohair@286 819 /**
ohair@286 820 * Returns true if the specified sub-type is an XML type.
ohair@286 821 */
ohair@286 822 private boolean isXml(String subType) {
ohair@286 823 return subType.equals("xml") || subType.endsWith("+xml");
ohair@286 824 }
ohair@286 825
ohair@286 826 /**
ohair@286 827 * Returns true if the {@link #initiatingType} is restricted
ohair@286 828 * to '0' and '1'. This logic is not complete, but it at least
ohair@286 829 * finds the such definition in SOAP @mustUnderstand.
ohair@286 830 */
ohair@286 831 private boolean isRestrictedTo0And1() {
ohair@286 832 XSFacet pattern = initiatingType.getFacet(XSFacet.FACET_PATTERN);
ohair@286 833 if(pattern!=null) {
ohair@286 834 String v = pattern.getValue().value;
ohair@286 835 if(v.equals("0|1") || v.equals("1|0") || v.equals("\\d"))
ohair@286 836 return true;
ohair@286 837 }
ohair@286 838 XSFacet enumf = initiatingType.getFacet(XSFacet.FACET_ENUMERATION);
ohair@286 839 if(enumf!=null) {
ohair@286 840 String v = enumf.getValue().value;
ohair@286 841 if(v.equals("0") || v.equals("1"))
ohair@286 842 return true;
ohair@286 843 }
ohair@286 844 return false;
ohair@286 845 }
ohair@286 846
ohair@286 847 private BigInteger readFacet(String facetName,int offset) {
ohair@286 848 XSFacet me = initiatingType.getFacet(facetName);
ohair@286 849 if(me==null)
ohair@286 850 return null;
alanb@368 851 BigInteger bi = DatatypeConverter.parseInteger(me.getValue().value);
ohair@286 852 if(offset!=0)
ohair@286 853 bi = bi.add(BigInteger.valueOf(offset));
ohair@286 854 return bi;
ohair@286 855 }
ohair@286 856
ohair@286 857 private BigInteger min(BigInteger a, BigInteger b) {
ohair@286 858 if(a==null) return b;
ohair@286 859 if(b==null) return a;
ohair@286 860 return a.min(b);
ohair@286 861 }
ohair@286 862
ohair@286 863 private BigInteger max(BigInteger a, BigInteger b) {
ohair@286 864 if(a==null) return b;
ohair@286 865 if(b==null) return a;
ohair@286 866 return a.max(b);
ohair@286 867 }
ohair@286 868
ohair@286 869 private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
ohair@286 870 private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
ohair@286 871 private static final BigInteger INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
ohair@286 872 private static final BigInteger INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
ohair@286 873
ohair@286 874 static {
ohair@286 875 // list of datatypes which have built-in conversions.
ohair@286 876 // note that although xs:token and xs:normalizedString are not
ohair@286 877 // specified in the spec, they need to be here because they
ohair@286 878 // have different whitespace normalization semantics.
ohair@286 879 Map<String,TypeUse> m = builtinConversions;
ohair@286 880
ohair@286 881 // TODO: this is so dumb
ohair@286 882 m.put("string", CBuiltinLeafInfo.STRING);
ohair@286 883 m.put("anyURI", CBuiltinLeafInfo.STRING);
ohair@286 884 m.put("boolean", CBuiltinLeafInfo.BOOLEAN);
ohair@286 885 // we'll also look at the expected media type, so don't just add this to the map
ohair@286 886 // m.put("base64Binary", CBuiltinLeafInfo.BASE64_BYTE_ARRAY);
ohair@286 887 m.put("hexBinary", CBuiltinLeafInfo.HEXBIN_BYTE_ARRAY);
ohair@286 888 m.put("float", CBuiltinLeafInfo.FLOAT);
ohair@286 889 m.put("decimal", CBuiltinLeafInfo.BIG_DECIMAL);
ohair@286 890 m.put("integer", CBuiltinLeafInfo.BIG_INTEGER);
ohair@286 891 m.put("long", CBuiltinLeafInfo.LONG);
ohair@286 892 m.put("unsignedInt", CBuiltinLeafInfo.LONG);
ohair@286 893 m.put("int", CBuiltinLeafInfo.INT);
ohair@286 894 m.put("unsignedShort", CBuiltinLeafInfo.INT);
ohair@286 895 m.put("short", CBuiltinLeafInfo.SHORT);
ohair@286 896 m.put("unsignedByte", CBuiltinLeafInfo.SHORT);
ohair@286 897 m.put("byte", CBuiltinLeafInfo.BYTE);
ohair@286 898 m.put("double", CBuiltinLeafInfo.DOUBLE);
ohair@286 899 m.put("QName", CBuiltinLeafInfo.QNAME);
ohair@286 900 m.put("NOTATION", CBuiltinLeafInfo.QNAME);
ohair@286 901 m.put("dateTime", CBuiltinLeafInfo.CALENDAR);
ohair@286 902 m.put("date", CBuiltinLeafInfo.CALENDAR);
ohair@286 903 m.put("time", CBuiltinLeafInfo.CALENDAR);
ohair@286 904 m.put("gYearMonth", CBuiltinLeafInfo.CALENDAR);
ohair@286 905 m.put("gYear", CBuiltinLeafInfo.CALENDAR);
ohair@286 906 m.put("gMonthDay", CBuiltinLeafInfo.CALENDAR);
ohair@286 907 m.put("gDay", CBuiltinLeafInfo.CALENDAR);
ohair@286 908 m.put("gMonth", CBuiltinLeafInfo.CALENDAR);
ohair@286 909 m.put("duration", CBuiltinLeafInfo.DURATION);
ohair@286 910 m.put("token", CBuiltinLeafInfo.TOKEN);
ohair@286 911 m.put("normalizedString",CBuiltinLeafInfo.NORMALIZED_STRING);
ohair@286 912 m.put("ID", CBuiltinLeafInfo.ID);
ohair@286 913 m.put("IDREF", CBuiltinLeafInfo.IDREF);
ohair@286 914 // TODO: handling dateTime, time, and date type
ohair@286 915 // String[] names = {
ohair@286 916 // "date", "dateTime", "time", "hexBinary" };
ohair@286 917 }
ohair@286 918 }

mercurial