/*
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.tools.internal.xjc.reader.xmlschema.bindinfo;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.namespace.QName;
import com.sun.codemodel.internal.ClassType;
import com.sun.codemodel.internal.JClassAlreadyExistsException;
import com.sun.codemodel.internal.JCodeModel;
import com.sun.codemodel.internal.JDefinedClass;
import com.sun.tools.internal.xjc.ErrorReceiver;
import com.sun.tools.internal.xjc.generator.bean.ImplStructureStrategy;
import static com.sun.tools.internal.xjc.generator.bean.ImplStructureStrategy.BEAN_ONLY;
import com.sun.tools.internal.xjc.model.Model;
import com.sun.tools.internal.xjc.reader.Const;
import com.sun.tools.internal.xjc.reader.Ring;
import com.sun.tools.internal.xjc.reader.xmlschema.SimpleTypeBuilder;
import com.sun.tools.internal.xjc.util.ReadOnlyAdapter;
import com.sun.xml.internal.bind.api.impl.NameConverter;
import com.sun.xml.internal.bind.v2.WellKnownNamespace;
import com.sun.xml.internal.xsom.XSDeclaration;
import com.sun.xml.internal.xsom.XSSchemaSet;
import com.sun.xml.internal.xsom.XSSimpleType;
Global binding customization. The code is highly temporary.
One of the information contained in a global customization
is the default binding for properties. This object contains a
BIProperty object to keep this information.
Author:
Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
/**
* Global binding customization. The code is highly temporary.
*
* <p>
* One of the information contained in a global customization
* is the default binding for properties. This object contains a
* BIProperty object to keep this information.
*
* @author
* Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
*/
@XmlRootElement(name="globalBindings")
public final class BIGlobalBinding extends AbstractDeclarationImpl {
Gets the name converter that will govern the XML -> Java
name conversion process for this compilation.
The "underscoreBinding" customization will determine
the exact object returned from this method. The rest of XJC
should just use the NameConverter interface.
Always non-null.
/**
* Gets the name converter that will govern the {@code XML -> Java}
* name conversion process for this compilation.
*
* <p>
* The "underscoreBinding" customization will determine
* the exact object returned from this method. The rest of XJC
* should just use the NameConverter interface.
*
* <p>
* Always non-null.
*/
@XmlTransient
public NameConverter nameConverter = NameConverter.standard;
// JAXB will use this property to set nameConverter
@XmlAttribute
void setUnderscoreBinding( UnderscoreBinding ub ) {
nameConverter = ub.nc;
}
UnderscoreBinding getUnderscoreBinding() {
throw new IllegalStateException(); // no need for this
}
public JDefinedClass getSuperClass() {
if(superClass==null) return null;
return superClass.getClazz(ClassType.CLASS);
}
public JDefinedClass getSuperInterface() {
if(superInterface==null) return null;
return superInterface.getClazz(ClassType.INTERFACE);
}
public BIProperty getDefaultProperty() {
return defaultProperty;
}
public boolean isJavaNamingConventionEnabled() {
return isJavaNamingConventionEnabled;
}
public BISerializable getSerializable() {
return serializable;
}
public boolean isGenerateElementClass() {
return generateElementClass;
}
public boolean isGenerateMixedExtensions() {
return generateMixedExtensions;
}
public boolean isChoiceContentPropertyEnabled() {
return choiceContentProperty;
}
public int getDefaultEnumMemberSizeCap() {
return defaultEnumMemberSizeCap;
}
public boolean isSimpleMode() {
return simpleMode!=null;
}
public boolean isRestrictionFreshType() {
return treatRestrictionLikeNewType !=null;
}
public EnumMemberMode getEnumMemberMode() {
return generateEnumMemberName;
}
public boolean isSimpleTypeSubstitution() {
return simpleTypeSubstitution;
}
public ImplStructureStrategy getCodeGenerationStrategy() {
return codeGenerationStrategy;
}
public LocalScoping getFlattenClasses() {
return flattenClasses;
}
Performs error check
/**
* Performs error check
*/
public void errorCheck() {
ErrorReceiver er = Ring.get(ErrorReceiver.class);
for (QName n : enumBaseTypes) {
XSSchemaSet xs = Ring.get(XSSchemaSet.class);
XSSimpleType st = xs.getSimpleType(n.getNamespaceURI(), n.getLocalPart());
if(st==null) {
er.error(loc,Messages.ERR_UNDEFINED_SIMPLE_TYPE.format(n));
continue;
}
if(!SimpleTypeBuilder.canBeMappedToTypeSafeEnum(st)) {
er.error(loc,Messages.ERR_CANNOT_BE_BOUND_TO_SIMPLETYPE.format(n));
continue;
}
}
}
private static enum UnderscoreBinding {
@XmlEnumValue("asWordSeparator")
WORD_SEPARATOR(NameConverter.standard),
@XmlEnumValue("asCharInWord")
CHAR_IN_WORD(NameConverter.jaxrpcCompatible);
final NameConverter nc;
UnderscoreBinding(NameConverter nc) {
this.nc = nc;
}
}
Returns true if the "isJavaNamingConventionEnabled" option is turned on.
In this mode, the compiler is expected to apply XML-to-Java name
conversion algorithm even to names given by customizations.
This method is intended to be called by other BIXXX classes.
The effect of this switch should be hidden inside this package.
IOW, the reader.xmlschema package shouldn't be aware of this switch.
/**
* Returns true if the "isJavaNamingConventionEnabled" option is turned on.
*
* In this mode, the compiler is expected to apply XML-to-Java name
* conversion algorithm even to names given by customizations.
*
* This method is intended to be called by other BIXXX classes.
* The effect of this switch should be hidden inside this package.
* IOW, the reader.xmlschema package shouldn't be aware of this switch.
*/
@XmlAttribute(name="enableJavaNamingConventions")
/*package*/ boolean isJavaNamingConventionEnabled = true;
True to generate classes for every simple type.
/**
* True to generate classes for every simple type.
*/
@XmlAttribute(name="mapSimpleTypeDef")
boolean simpleTypeSubstitution = false;
Gets the default defaultProperty customization.
/**
* Gets the default defaultProperty customization.
*/
@XmlTransient
private BIProperty defaultProperty;
/*
Three properties used to construct a default property
*/
@XmlAttribute
private boolean fixedAttributeAsConstantProperty = false;
@XmlAttribute
private CollectionTypeAttribute collectionType = new CollectionTypeAttribute();
@XmlAttribute
void setGenerateIsSetMethod(boolean b) {
optionalProperty = b ? OptionalPropertyMode.ISSET : OptionalPropertyMode.WRAPPER;
}
Returns true if the compiler needs to generate type-safe enum
member names when enumeration values cannot be used as constant names.
/**
* Returns true if the compiler needs to generate type-safe enum
* member names when enumeration values cannot be used as constant names.
*/
@XmlAttribute(name="typesafeEnumMemberName")
EnumMemberMode generateEnumMemberName = EnumMemberMode.SKIP;
The code generation strategy.
/**
* The code generation strategy.
*/
@XmlAttribute(name="generateValueClass")
ImplStructureStrategy codeGenerationStrategy = BEAN_ONLY;
Set of datatype names. For a type-safe enum class
to be generated, the underlying XML datatype must be derived from
one of the types in this set.
/**
* Set of datatype names. For a type-safe enum class
* to be generated, the underlying XML datatype must be derived from
* one of the types in this set.
*/
// default value is set in the post-init action
@XmlAttribute(name="typesafeEnumBase")
private Set<QName> enumBaseTypes;
Returns BISerializable
if the extension is specified, or null otherwise. /**
* Returns {@link BISerializable} if the extension is specified,
* or null otherwise.
*/
@XmlElement
private BISerializable serializable = null;
If <xjc:superClass>
extension is specified, returns the specified root class. Otherwise null. /**
* If {@code <xjc:superClass>} extension is specified,
* returns the specified root class. Otherwise null.
*/
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
ClassNameBean superClass = null;
If <xjc:superInterface>
extension is specified, returns the specified root class. Otherwise null. /**
* If {@code <xjc:superInterface>} extension is specified,
* returns the specified root class. Otherwise null.
*/
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
ClassNameBean superInterface = null;
Generate the simpler optimized code, but not necessarily
conforming to the spec.
/**
* Generate the simpler optimized code, but not necessarily
* conforming to the spec.
*/
@XmlElement(name="simple",namespace=Const.XJC_EXTENSION_URI)
String simpleMode = null;
Handles complex type restriction as if it were a new type.
/**
* Handles complex type restriction as if it were a new type.
*/
@XmlElement(name="treatRestrictionLikeNewType",namespace=Const.XJC_EXTENSION_URI)
String treatRestrictionLikeNewType = null;
True to generate a class for elements by default.
/**
* True to generate a class for elements by default.
*/
@XmlAttribute
boolean generateElementClass = false;
@XmlAttribute
boolean generateMixedExtensions = false;
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
Boolean generateElementProperty = null;
@XmlAttribute(name="generateElementProperty") // for JAXB unmarshaller
private void setGenerateElementPropertyStd(boolean value) {
generateElementProperty = value;
}
@XmlAttribute
boolean choiceContentProperty = false;
@XmlAttribute
OptionalPropertyMode optionalProperty = OptionalPropertyMode.WRAPPER;
Default cap to the number of constants in the enum.
We won't attempt to produce a type-safe enum by default
if there are more enumeration facets than specified in this field.
/**
* Default cap to the number of constants in the enum.
* We won't attempt to produce a type-safe enum by default
* if there are more enumeration facets than specified in this field.
*/
@XmlAttribute(name="typesafeEnumMaxMembers")
int defaultEnumMemberSizeCap = 256;
If true, interfaces/classes that are normally generated as a nested interface/class
will be generated into the package, allowing the generated classes to be flat.
See Bug 4969415 for the motivation.
/**
* If true, interfaces/classes that are normally generated as a nested interface/class
* will be generated into the package, allowing the generated classes to be flat.
*
* See <a href="http://monaco.sfbay/detail.jsf?cr=4969415">Bug 4969415</a> for the motivation.
*/
@XmlAttribute(name="localScoping")
LocalScoping flattenClasses = LocalScoping.NESTED;
Globally-defined conversion customizations.
See Also: - setGlobalConversions
/**
* Globally-defined conversion customizations.
*
* @see #setGlobalConversions
*/
@XmlTransient
private final Map<QName,BIConversion> globalConversions = new HashMap<QName, BIConversion>();
// method for JAXB unmarshaller
@XmlElement(name="javaType")
private void setGlobalConversions(GlobalStandardConversion[] convs) {
for (GlobalStandardConversion u : convs) {
globalConversions.put(u.xmlType,u);
}
}
@XmlElement(name="javaType",namespace=Const.XJC_EXTENSION_URI)
private void setGlobalConversions2(GlobalVendorConversion[] convs) {
for (GlobalVendorConversion u : convs) {
globalConversions.put(u.xmlType,u);
}
}
//
// these customizations were valid in 1.0, but in 2.0 we don't
// use them. OTOH, we don't want to issue an error for them,
// so we just define a mapping and ignore the value.
//
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
String noMarshaller = null;
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
String noUnmarshaller = null;
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
String noValidator = null;
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
String noValidatingUnmarshaller = null;
@XmlElement(namespace=Const.XJC_EXTENSION_URI)
TypeSubstitutionElement typeSubstitution = null;
Another 1.0 compatibility customization (but we accept it and treat it as serializable
) /**
* Another 1.0 compatibility customization (but we accept it
* and treat it as {@link #serializable})
*/
@XmlElement(name="serializable",namespace=Const.XJC_EXTENSION_URI)
void setXjcSerializable(BISerializable s) {
this.serializable = s;
}
private static final class TypeSubstitutionElement {
@XmlAttribute
String type;
}
public void onSetOwner() {
super.onSetOwner();
// if one is given by options, use that
NameConverter nc = Ring.get(Model.class).options.getNameConverter();
if(nc!=null)
nameConverter = nc;
}
Creates a bind info object with the default values
/**
* Creates a bind info object with the default values
*/
public BIGlobalBinding() {
}
public void setParent(BindInfo parent) {
super.setParent(parent);
// fill in the remaining default values
if(enumBaseTypes==null)
enumBaseTypes = Collections.singleton(new QName(WellKnownNamespace.XML_SCHEMA,"string"));
this.defaultProperty = new BIProperty(getLocation(),null,null,null,
collectionType, fixedAttributeAsConstantProperty, optionalProperty, generateElementProperty );
defaultProperty.setParent(parent); // don't forget to initialize the defaultProperty
}
Moves global BIConversion to the right object.
/**
* Moves global BIConversion to the right object.
*/
public void dispatchGlobalConversions( XSSchemaSet schema ) {
// also set parent to the global conversions
for( Map.Entry<QName,BIConversion> e : globalConversions.entrySet() ) {
QName name = e.getKey();
BIConversion conv = e.getValue();
XSSimpleType st = schema.getSimpleType(name.getNamespaceURI(),name.getLocalPart());
if(st==null) {
Ring.get(ErrorReceiver.class).error(
getLocation(),
Messages.ERR_UNDEFINED_SIMPLE_TYPE.format(name)
);
continue; // abort
}
getBuilder().getOrCreateBindInfo(st).addDecl(conv);
}
}
Checks if the given XML Schema built-in type can be mapped to
a type-safe enum class.
Params: - typeName –
/**
* Checks if the given XML Schema built-in type can be mapped to
* a type-safe enum class.
*
* @param typeName
*/
public boolean canBeMappedToTypeSafeEnum( QName typeName ) {
return enumBaseTypes.contains(typeName);
}
public boolean canBeMappedToTypeSafeEnum( String nsUri, String localName ) {
return canBeMappedToTypeSafeEnum(new QName(nsUri,localName));
}
public boolean canBeMappedToTypeSafeEnum( XSDeclaration decl ) {
return canBeMappedToTypeSafeEnum( decl.getTargetNamespace(), decl.getName() );
}
public QName getName() { return NAME; }
public static final QName NAME = new QName(
Const.JAXB_NSURI, "globalBindings" );
Used to unmarshal
<[element] name="className" />
/**
* Used to unmarshal
* <pre>{@code
* <[element] name="className" />
* }</pre>
*/
static final class ClassNameBean {
@XmlAttribute(required=true)
String name;
Computed from name
on demand. /**
* Computed from {@link #name} on demand.
*/
@XmlTransient
JDefinedClass clazz;
JDefinedClass getClazz(ClassType t) {
if (clazz != null) return clazz;
try {
JCodeModel codeModel = Ring.get(JCodeModel.class);
clazz = codeModel._class(name, t);
clazz.hide();
return clazz;
} catch (JClassAlreadyExistsException e) {
return e.getExistingClass();
}
}
}
static final class ClassNameAdapter extends ReadOnlyAdapter<ClassNameBean,String> {
public String unmarshal(ClassNameBean bean) throws Exception {
return bean.name;
}
}
Global <jaxb:javaType>
. /**
* Global {@code <jaxb:javaType>}.
*/
static final class GlobalStandardConversion extends BIConversion.User {
@XmlAttribute
QName xmlType;
@Override
public boolean equals(Object obj) {
if(obj instanceof GlobalStandardConversion) {
return ((GlobalStandardConversion)obj).xmlType.equals(xmlType);
}
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 73 * hash + (this.xmlType != null ? this.xmlType.hashCode() : 0);
return hash;
}
}
Global <xjc:javaType>
. /**
* Global {@code <xjc:javaType>}.
*/
static final class GlobalVendorConversion extends BIConversion.UserAdapter {
@XmlAttribute
QName xmlType;
@Override
public boolean equals(Object obj) {
if(obj instanceof GlobalVendorConversion) {
return ((GlobalVendorConversion)obj).xmlType.equals(xmlType);
}
return false;
}
@Override
public int hashCode() {
int hash = 7;
hash = 73 * hash + (this.xmlType != null ? this.xmlType.hashCode() : 0);
return hash;
}
}
/* don't want to override equals to avoid overriding hashcode for this complex object, too */
public boolean isEqual(BIGlobalBinding b) {
boolean equal =
this.isJavaNamingConventionEnabled == b.isJavaNamingConventionEnabled &&
this.simpleTypeSubstitution == b.simpleTypeSubstitution &&
this.fixedAttributeAsConstantProperty == b.fixedAttributeAsConstantProperty &&
this.generateEnumMemberName == b.generateEnumMemberName &&
this.codeGenerationStrategy == b.codeGenerationStrategy &&
this.serializable == b.serializable &&
this.superClass == b.superClass &&
this.superInterface == b.superInterface &&
this.generateElementClass == b.generateElementClass &&
this.generateMixedExtensions == b.generateMixedExtensions &&
this.generateElementProperty == b.generateElementProperty &&
this.choiceContentProperty == b.choiceContentProperty &&
this.optionalProperty == b.optionalProperty &&
this.defaultEnumMemberSizeCap == b.defaultEnumMemberSizeCap &&
this.flattenClasses == b.flattenClasses;
if (!equal) return false;
return isEqual(this.nameConverter, b.nameConverter) &&
isEqual(this.noMarshaller, b.noMarshaller) &&
isEqual(this.noUnmarshaller, b.noUnmarshaller) &&
isEqual(this.noValidator, b.noValidator) &&
isEqual(this.noValidatingUnmarshaller, b.noValidatingUnmarshaller) &&
isEqual(this.typeSubstitution, b.typeSubstitution) &&
isEqual(this.simpleMode, b.simpleMode) &&
isEqual(this.enumBaseTypes, b.enumBaseTypes) &&
isEqual(this.treatRestrictionLikeNewType, b.treatRestrictionLikeNewType) &&
isEqual(this.globalConversions, b.globalConversions);
}
private boolean isEqual(Object a, Object b) {
if (a != null) {
return a.equals(b);
}
return (b == null);
}
}