| /* Copyright 2004 The Apache Software Foundation |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.xmlbeans.impl.binding.compile; |
| |
| import org.apache.xmlbeans.impl.binding.bts.*; |
| import org.apache.xmlbeans.impl.binding.tylar.TylarWriter; |
| import org.apache.xmlbeans.impl.binding.tylar.TylarConstants; |
| import org.apache.xmlbeans.impl.binding.tylar.ExplodedTylarImpl; |
| import org.apache.xmlbeans.impl.binding.tylar.DebugTylarWriter; |
| import org.apache.xmlbeans.impl.binding.joust.Variable; |
| import org.apache.xmlbeans.impl.binding.joust.CompilingJavaOutputStream; |
| import org.apache.xmlbeans.impl.binding.joust.JavaOutputStream; |
| import org.apache.xmlbeans.impl.common.NameUtil; |
| import org.apache.xmlbeans.*; |
| import org.apache.xmlbeans.soap.SOAPArrayType; |
| import org.apache.xmlbeans.soap.SchemaWSDLArrayType; |
| import org.w3.x2001.xmlSchema.SchemaDocument; |
| |
| import javax.xml.namespace.QName; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.LinkedHashMap; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.HashMap; |
| import java.util.Collections; |
| import java.util.AbstractCollection; |
| import java.util.List; |
| import java.math.BigInteger; |
| import java.io.*; |
| import java.lang.reflect.Modifier; |
| |
| /** |
| * This is the "JAXRPC-style" Schema-to-bts compiler. |
| */ |
| public class Schema2Java extends BindingCompiler { |
| |
| // ======================================================================== |
| // Variables |
| |
| private Set usedNames = new HashSet(); |
| private Set duplicateNames = new HashSet(); |
| private SchemaTypeSystem sts = null; |
| private Map scratchFromXmlName = new LinkedHashMap(); |
| private Map scratchFromSchemaType = new HashMap(); // for convenience |
| private Map scratchFromJavaNameString = new HashMap(); // for printing |
| private BindingLoader mLoader; |
| private int structureCount; |
| private BindingFile bindingFile = new BindingFile(); |
| private JavaOutputStream mJoust = null; |
| private CompilingJavaOutputStream mDefaultJoust = null; |
| private boolean mJaxRpcRules; |
| |
| // ======================================================================== |
| // Constants |
| |
| private static String[] PRIMITIVE_TYPES = |
| {"int", "boolean", "float", "long", "double", "short", "byte", "char"}; |
| private static String[] BOXED_TYPES = |
| {"java.lang.Integer", "java.lang.Boolean", "java.lang.Float", |
| "java.lang.Long", "java.lang.Double", "java.lang.Short", "java.lang.Byte", |
| "java.lang.Character"}; |
| private static String WILDCARD_ELEMENT_MAPPING = "javax.xml.soap.SOAPElement"; |
| private static String WILDCARD_ATTRIBUTE_MAPPING = "javax.xml.soap.SOAPElement"; |
| private static final String xsns = "http://www.w3.org/2001/XMLSchema"; |
| |
| // ======================================================================== |
| // Constructors |
| |
| /** |
| * Consturcts a Schema2Java to bind the types in the given type system. |
| */ |
| public Schema2Java(SchemaTypeSystem s) { |
| setSchemaTypeSystem(s); |
| } |
| |
| /** |
| * If you use this, you absolutely have to call setInput later. This is |
| * here just as a convenience for Schema2JavaTask. |
| */ |
| /*package*/ |
| Schema2Java() { |
| } |
| |
| /*package*/ |
| void setSchemaTypeSystem(SchemaTypeSystem s) { |
| if (s == null) throw new IllegalArgumentException("null sts"); |
| sts = s; |
| } |
| |
| // ======================================================================== |
| // Public methods |
| |
| /** |
| * Sets whether javac should be run on the generated java sources. |
| * The default is true. |
| */ |
| public void setCompileJava(boolean b) { |
| assertCompilationStarted(false); |
| getDefaultJoust().setDoCompile(b); |
| } |
| |
| /** |
| * Sets the location of javac to be invoked. Default compiler is used |
| * if this is not set. Ignored if doCompile is set to false. Also note |
| * that not all BindingCompilers generate any source code at all, so |
| * setting this may have no effect. |
| */ |
| public void setJavac(String javacPath) { |
| assertCompilationStarted(false); |
| getDefaultJoust().setJavac(javacPath); |
| } |
| |
| /** |
| * Sets the classpath to use for compilation of generated sources. |
| * The System classpath is used by default. This is ignored if doCompile is |
| * false. Also note that not all BindingCompilers generate any source |
| * code at all, so setting this may have no effect. |
| */ |
| public void setJavacClasspath(File[] classpath) { |
| assertCompilationStarted(false); |
| getDefaultJoust().setJavacClasspath(classpath); |
| } |
| |
| /** |
| * Sets whether this BindingCompiler should keep any generated java source |
| * code it generates. The default is true. This will have no effect if |
| * doCompile is set to false. Also note that not all BindingCompilers |
| * generate any source code at all, so setting this may have no effect in |
| * any event. |
| */ |
| public void setKeepGeneratedJava(boolean b) { |
| assertCompilationStarted(false); |
| getDefaultJoust().setKeepGenerated(b); |
| } |
| |
| /** |
| * Sets whether the compiler should use the JAX-RPC rules for mapping simple |
| * types and XMLNames to Java. By default, the XMLBeans rules are used, |
| * which are in fact almost identical. |
| */ |
| public void setJaxRpcRules(boolean b) { |
| assertCompilationStarted(false); |
| mJaxRpcRules = b; |
| } |
| |
| // ======================================================================== |
| // BindingCompiler implementation |
| |
| /** |
| * We override this method because we need the bindAs... tylar to include |
| * the defaultJoust. |
| */ |
| protected ExplodedTylarImpl createDefaultExplodedTylarImpl(File tylarDestDir) |
| throws IOException { |
| CompilingJavaOutputStream joust = getDefaultJoust(); |
| joust.setSourceDir(new File(tylarDestDir, TylarConstants.SRC_ROOT)); |
| joust.setCompilationDir(tylarDestDir); |
| mJoust = joust; |
| return ExplodedTylarImpl.create(tylarDestDir, mJoust); |
| } |
| |
| /** |
| * Computes the binding. Note that the given TylarWriter MUST provide |
| * a JavaOutputStream or an IllegalArgumentException will be thrown. Note |
| * also that if you call this method, the various parameters on this object |
| * pertaining to java compilation (e.g. setJavacPath) will be ignored. |
| */ |
| protected void internalBind(TylarWriter writer) { |
| if (sts == null) throw new IllegalStateException("SchemaTypeSystem not set"); |
| if ((mJoust = writer.getJavaOutputStream()) == null) { |
| //sanity check |
| throw new IllegalArgumentException("The specified TylarWriter does not " + |
| "provide a JavaOutputStream, and so it cannot be used with " + |
| "schema2java."); |
| } |
| bind(); |
| try { |
| writer.writeBindingFile(bindingFile); |
| writer.writeSchemaTypeSystem(sts); |
| } catch (IOException ioe) { |
| if (!logError(ioe)) return; |
| } |
| //FIXME also write the input schemas |
| writeJavaFiles(); |
| } |
| |
| // ======================================================================== |
| // Private methods |
| |
| private CompilingJavaOutputStream getDefaultJoust() { |
| if (mDefaultJoust == null) { |
| mDefaultJoust = new CompilingJavaOutputStream(); |
| mDefaultJoust.setLogger(this); |
| } |
| return mDefaultJoust; |
| } |
| |
| private void bind() { |
| //sanity check |
| if (mJoust == null) throw new IllegalStateException("joust not set"); |
| |
| setBuiltinBindingLoader(BuiltinBindingLoader.getBuiltinBindingLoader(mJaxRpcRules)); |
| mLoader = super.getBaseBindingLoader(); |
| |
| // Every type or global element or global attribute is dropped into |
| // one of a number of categories. (See Scratch constants.) |
| // |
| // Based on the category, a java class is either defined or found |
| // that maches with the schema type. |
| // |
| // The phases work as follows: |
| // |
| // 1. categorize and allocate Scratches |
| // 2. write or find java names for each xml type |
| // 3. allocate binding types for each scratch (done in the same pass as 2) |
| // 4. fill in the java getter/setter structure of any complex types |
| |
| |
| // 1. categorize and allocate Scratches |
| createScratchArea(); |
| |
| // Compute the list of duplicate names for Java types |
| for (Iterator i = scratchIterator(); i.hasNext();) { |
| Scratch scratch = (Scratch) i.next(); |
| if (scratch.getCategory() == Scratch.STRUCT_TYPE || |
| scratch.getCategory() == Scratch.ENUM_TYPE) |
| { |
| SchemaType sType = scratch.getSchemaType(); |
| String name = getDefaultJavaName(sType).toLowerCase(); |
| if (usedNames.contains(name)) |
| duplicateNames.add(name); |
| usedNames.add(name); |
| } |
| } |
| usedNames.clear(); |
| |
| // 2. write or find java names for each xml type |
| // 3. allocate binding types for each scratch (done in the same pass as 2) |
| for (Iterator i = scratchIterator(); i.hasNext();) { |
| Scratch scratch = (Scratch) i.next(); |
| resolveJavaName(scratch); |
| createBindingType(scratch); |
| } |
| |
| // 4. fill in the java getter/setter structure of any complex types |
| for (Iterator i = scratchIterator(); i.hasNext();) { |
| Scratch scratch = (Scratch) i.next(); |
| resolveJavaStructure(scratch); |
| resolveJavaEnumeration(scratch); |
| resolveJavaArray(scratch); |
| } |
| } |
| |
| /** |
| * This function goes through all relevant schema types, plus soap |
| * array types, and creates a scratch area for each. Each |
| * scratch area is also marked at this time with an XmlTypeName, |
| * a schema type, and a category. |
| */ |
| private void createScratchArea() { |
| logVerbose("creating scratch area..."); |
| for (Iterator i = allTypeIterator(); i.hasNext();) { |
| SchemaType sType = (SchemaType) i.next(); |
| logVerbose("processing schema type "+sType); |
| |
| XmlTypeName xmlName = XmlTypeName.forSchemaType(sType); |
| Scratch scratch; |
| |
| if (sType.isSimpleType()) { |
| // simple types are atomic |
| // the order of these checks is important: an enumeration of lists will |
| // be both an enumeration and a list |
| // todo: what about simple content, custom codecs, etc? |
| if (isEnumeration(sType)) |
| scratch = new Scratch(sType, xmlName, Scratch.ENUM_TYPE); |
| else if (isList(sType)) |
| scratch = new Scratch(sType, xmlName, Scratch.LIST_TYPE); |
| else |
| scratch = new Scratch(sType, xmlName, Scratch.ATOMIC_TYPE); |
| } else if (sType.isDocumentType()) { |
| scratch = new Scratch(sType, XmlTypeName.forGlobalName(XmlTypeName.ELEMENT, sType.getDocumentElementName()), Scratch.ELEMENT); |
| } else if (sType.isAttributeType()) { |
| scratch = new Scratch(sType, XmlTypeName.forGlobalName(XmlTypeName.ATTRIBUTE, sType.getAttributeTypeAttributeName()), Scratch.ATTRIBUTE); |
| } else if (isSoapArray(sType)) { |
| scratch = new Scratch(sType, xmlName, Scratch.SOAPARRAY_REF); |
| XmlTypeName altXmlName = soapArrayTypeName(sType); |
| scratch.setAsIf(altXmlName); |
| |
| // soap arrays unroll like this |
| while (altXmlName.getComponentType() == XmlTypeName.SOAP_ARRAY) { |
| Scratch altScratch = new Scratch(sType, altXmlName, Scratch.SOAPARRAY); |
| scratchFromXmlName.put(altXmlName, altScratch); |
| altXmlName = altXmlName.getOuterComponent(); |
| } |
| } else if (isLiteralArray(sType)) { |
| scratch = new Scratch(sType, xmlName, Scratch.LITERALARRAY_TYPE); |
| } else { |
| scratch = new Scratch(sType, xmlName, Scratch.STRUCT_TYPE); |
| } |
| |
| scratchFromXmlName.put(xmlName, scratch); |
| scratchFromSchemaType.put(sType, scratch); |
| logVerbose("registered scratch "+scratch.getXmlName()+" for "+sType); |
| } |
| } |
| |
| /** |
| * Computes a JavaTypeName for each scratch. Notice that structures and |
| * atoms can be computed directly, but arrays, elements, etc, need |
| * to defer to other scratch areas, so this is a resolution |
| * process that occurs in dependency order. |
| */ |
| private void resolveJavaName(Scratch scratch) { |
| if (scratch == null) { |
| logVerbose("FIXME null scratch, ignoring for now"); |
| return; |
| } |
| if (scratch == null) throw new IllegalArgumentException("null scratch"); |
| logVerbose("Resolving " + scratch.getXmlName()); |
| // already resolved (we recurse to do in dependency order) |
| if (scratch.getJavaName() != null) |
| return; |
| |
| switch (scratch.getCategory()) { |
| case Scratch.ATOMIC_TYPE: |
| { |
| resolveSimpleScratch(scratch); |
| return; |
| } |
| |
| case Scratch.STRUCT_TYPE: |
| case Scratch.ENUM_TYPE: |
| { |
| JavaTypeName javaName = pickUniqueJavaName(scratch.getSchemaType(), |
| scratch.getCategory() == Scratch.ENUM_TYPE); |
| structureCount += 1; |
| scratch.setJavaName(javaName); |
| scratchFromJavaNameString.put(javaName.toString(), scratch); |
| return; |
| } |
| |
| case Scratch.LIST_TYPE: |
| { |
| SchemaType itemType = getListItemType(scratch.getSchemaType()); |
| Scratch itemScratch = scratchForSchemaType(itemType); |
| JavaTypeName itemName = null; |
| if (itemScratch == null) { |
| itemName = getTypeNameFromLoader(itemType); |
| } |
| else { |
| // The type is in the current scratch area |
| resolveJavaName(itemScratch); |
| itemName = itemScratch.getJavaName(); |
| } |
| if (itemName != null) |
| scratch.setJavaName(JavaTypeName.forArray(itemName, 1)); |
| return; |
| } |
| case Scratch.LITERALARRAY_TYPE: |
| { |
| SchemaType itemType = getLiteralArrayItemType(scratch.getSchemaType()); |
| boolean nillable = scratch.getSchemaType(). |
| getProperties()[0].hasNillable() != SchemaProperty.NEVER; |
| Scratch itemScratch = scratchForSchemaType(itemType); |
| JavaTypeName itemName = null; |
| if (itemScratch == null) { |
| itemName = getTypeNameFromLoader(itemType); |
| } |
| else |
| { |
| resolveJavaName(itemScratch); |
| itemName = itemScratch.getJavaName(); |
| } |
| if (itemName != null) |
| if (nillable) |
| { |
| JavaTypeName boxedName = getBoxedName(itemName); |
| if (boxedName != null) |
| scratch.setJavaName(JavaTypeName.forArray(boxedName, 1)); |
| else |
| scratch.setJavaName(JavaTypeName.forArray(itemName, 1)); |
| } |
| else |
| scratch.setJavaName(JavaTypeName.forArray(itemName, 1)); |
| return; |
| } |
| |
| case Scratch.SOAPARRAY_REF: |
| { |
| XmlTypeName soapArrayName = scratch.getAsIf(); |
| Scratch arrayScratch = scratchForXmlName(soapArrayName); |
| resolveJavaName(arrayScratch); |
| scratch.setJavaName(arrayScratch.getJavaName()); |
| scratch.setAsIf(arrayScratch.getXmlName()); |
| return; |
| } |
| |
| case Scratch.SOAPARRAY: |
| { |
| XmlTypeName arrayName = scratch.getXmlName(); |
| XmlTypeName itemName = arrayName.getOuterComponent(); |
| Scratch itemScratch = scratchForXmlName(itemName); |
| JavaTypeName itemJavaName = null; |
| if (itemScratch == null) { |
| itemJavaName = getTypeNameFromLoader(itemName); |
| if (itemJavaName == null) { |
| logError("Could not find reference to type \"" + |
| itemName.getQName() + "\"", null, scratch.getSchemaType()); |
| itemJavaName = JavaTypeName.forString("unknown"); |
| } |
| } |
| else { |
| resolveJavaName(itemScratch); |
| itemJavaName = itemScratch.getJavaName(); |
| } |
| scratch.setJavaName(JavaTypeName.forArray(itemJavaName, arrayName.getNumber())); |
| return; |
| } |
| |
| case Scratch.ELEMENT: |
| case Scratch.ATTRIBUTE: |
| { |
| logVerbose("processing element "+scratch.getXmlName()); |
| SchemaType contentType = scratch.getSchemaType().getProperties()[0].getType(); |
| boolean nillable = scratch.getSchemaType(). |
| getProperties()[0].hasNillable() != SchemaProperty.NEVER; |
| logVerbose("content type is "+contentType.getName()); |
| JavaTypeName contentName = null; |
| Scratch contentScratch = scratchForSchemaType(contentType); |
| logVerbose("content scratch is "+contentScratch); |
| if (contentScratch == null) |
| { |
| XmlTypeName treatAs = XmlTypeName.forSchemaType(contentType); |
| BindingType bType = mLoader.getBindingType(mLoader. |
| lookupPojoFor(treatAs)); |
| if (bType != null) |
| { |
| contentName = bType.getName().getJavaName(); |
| scratch.setAsIf(treatAs); |
| } |
| else if (contentType.isBuiltinType()) |
| logError("Builtin type " + contentType.getName() + " is not supported", |
| null, contentType); |
| else |
| throw new IllegalStateException(contentType.getName().toString()+ |
| " type is not on mLoader"); |
| } |
| else |
| { |
| resolveJavaName(contentScratch); |
| contentName = contentScratch.getJavaName(); |
| scratch.setAsIf(contentScratch.getXmlName()); |
| } |
| if (contentName != null) |
| if (nillable) |
| { |
| JavaTypeName boxedName = getBoxedName(contentName); |
| if (boxedName != null) |
| scratch.setJavaName(boxedName); |
| else |
| scratch.setJavaName(contentName); |
| } |
| else |
| scratch.setJavaName(contentName); |
| return; |
| } |
| |
| default: |
| throw new IllegalStateException("Unrecognized category"); |
| } |
| } |
| |
| /** |
| * Computes a BindingType for a scratch. |
| */ |
| private void createBindingType(Scratch scratch) { |
| assert(scratch.getBindingType() == null); |
| logVerbose("createBindingType for "+scratch); |
| BindingTypeName btName = BindingTypeName.forPair(scratch.getJavaName(), scratch.getXmlName()); |
| |
| switch (scratch.getCategory()) { |
| case Scratch.ATOMIC_TYPE: |
| case Scratch.SOAPARRAY_REF: |
| case Scratch.ATTRIBUTE: |
| SimpleBindingType simpleResult = new SimpleBindingType(btName); |
| simpleResult.setAsIfXmlType(scratch.getAsIf()); |
| scratch.setBindingType(simpleResult); |
| bindingFile.addBindingType(simpleResult, shouldBeFromJavaDefault(btName), true); |
| break; |
| |
| case Scratch.ELEMENT: |
| SimpleDocumentBinding docResult = new SimpleDocumentBinding(btName); |
| docResult.setTypeOfElement(scratch.getAsIf()); |
| scratch.setBindingType(docResult); |
| bindingFile.addBindingType(docResult, shouldBeFromJavaDefault(btName), true); |
| break; |
| |
| case Scratch.STRUCT_TYPE: |
| BindingType structResult; |
| if (scratch.getSchemaType().getContentType() == SchemaType.SIMPLE_CONTENT) |
| structResult = new SimpleContentBean(btName); |
| else |
| structResult = new ByNameBean(btName); |
| scratch.setBindingType(structResult); |
| bindingFile.addBindingType(structResult, true, true); |
| break; |
| |
| case Scratch.ENUM_TYPE: |
| JaxrpcEnumType enumResult = new JaxrpcEnumType(btName); |
| enumResult.setGetValueMethod(JaxrpcEnumType.DEFAULT_GET_VALUE); |
| enumResult.setFromStringMethod(JaxrpcEnumType.DEFAULT_FROM_STRING); |
| enumResult.setToXMLMethod(JaxrpcEnumType.DEFAULT_TO_XML); |
| scratch.setBindingType(enumResult); |
| bindingFile.addBindingType(enumResult, true, true); |
| break; |
| |
| case Scratch.LIST_TYPE: |
| ListArrayType listResult = new ListArrayType(btName); |
| scratch.setBindingType(listResult); |
| bindingFile.addBindingType(listResult, shouldBeFromJavaDefault(btName), true); |
| break; |
| |
| case Scratch.LITERALARRAY_TYPE: |
| WrappedArrayType arrayResult = new WrappedArrayType(btName); |
| scratch.setBindingType(arrayResult); |
| bindingFile.addBindingType(arrayResult, shouldBeFromJavaDefault(btName), true); |
| break; |
| |
| case Scratch.SOAPARRAY: |
| SoapArrayType soapArray = new SoapArrayType(btName); |
| scratch.setBindingType(soapArray); |
| bindingFile.addBindingType(soapArray, shouldBeFromJavaDefault(btName), false); |
| break; |
| |
| default: |
| throw new IllegalStateException("Unrecognized category"); |
| } |
| } |
| |
| /** |
| * Returns true if the given btName would be the first (unique) |
| * default java->xml binding to be entered in the java-to-type or |
| * java-to-element tables. |
| */ |
| private boolean shouldBeFromJavaDefault(BindingTypeName btName) { |
| JavaTypeName jName = btName.getJavaName(); |
| XmlTypeName xName = btName.getXmlName(); |
| if (xName.isSchemaType()) { |
| return (bindingFile.lookupTypeFor(jName) == null && |
| mLoader.lookupTypeFor(jName) == null); |
| } |
| if (xName.getComponentType() == XmlTypeName.ELEMENT) { |
| return (bindingFile.lookupElementFor(jName) == null && |
| mLoader.lookupElementFor(jName) == null); |
| } |
| return false; |
| } |
| |
| /** |
| * Now we resolve the structural aspects (property names) for each |
| * scratch. |
| */ |
| private void resolveJavaStructure(Scratch scratch) { |
| if (scratch.getCategory() != Scratch.STRUCT_TYPE) |
| return; |
| |
| if (scratch.isStructureResolved()) |
| return; |
| |
| scratch.setStructureResolved(true); |
| |
| SchemaType schemaType = scratch.getSchemaType(); |
| SchemaType baseType = schemaType.getBaseType(); |
| int derivationType = schemaType.getDerivationType(); |
| Collection baseProperties = null; |
| if (baseType != null) |
| baseProperties = extractProperties(baseType); |
| if (baseProperties == null) |
| baseProperties = Collections.EMPTY_LIST; |
| |
| // sort properties based on QName attr/elt |
| Map seenAttrProps = new HashMap(); |
| Map seenEltProps = new HashMap(); |
| Set seenMethodNames = new HashSet(); |
| seenMethodNames.add("getClass"); |
| |
| for (Iterator i = baseProperties.iterator(); i.hasNext();) { |
| QNameProperty prop = (QNameProperty) i.next(); |
| if (prop.isAttribute()) |
| seenAttrProps.put(prop.getQName(), prop); |
| else |
| seenEltProps.put(prop.getQName(), prop); |
| |
| // todo: probably this collision avoidance should be using Java introspection instead |
| if (prop.getGetterName() != null) |
| seenMethodNames.add(prop.getGetterName()); |
| if (prop.getSetterName() != null) |
| seenMethodNames.add(prop.getSetterName()); |
| } |
| |
| if (schemaType.getContentType() == SchemaType.SIMPLE_CONTENT) { |
| // Go up the type hierarchy to find the first simple type ancestor of |
| // this complex type |
| while (!baseType.isSimpleType()) |
| baseType = baseType.getBaseType(); |
| // we have to add a '_value' property to hold the value corresponding to the |
| // content of the XML elem |
| BindingType bType = extractBindingType(baseType); |
| if (bType == null) |
| throw new IllegalStateException("Type " + baseType.getName() + |
| "not found in type loader"); |
| String propName = "_value"; |
| SimpleContentProperty prop = new SimpleContentProperty(); |
| prop.setSetterName(MethodName.create("set" + propName, |
| bType.getName().getJavaName())); |
| prop.setGetterName(MethodName.create("get" + propName)); |
| prop.setBindingType(bType); |
| scratch.setSimpleContentProperty(prop); |
| } |
| else { |
| // Handle the element wildcards |
| if (schemaType.hasElementWildcards()) { |
| // First, we have to see if it's just one wildcard or more |
| boolean multiple = countWildcards(schemaType.getContentModel()) > 1; |
| // We have to look at the base type and check multiplicity |
| if (baseType != null && |
| baseType.getBuiltinTypeCode() != SchemaType.BTC_ANY_TYPE) { |
| boolean hasBaseElementWildcards = baseType.hasElementWildcards(); |
| boolean baseMultiple = countWildcards(baseType.getContentModel()) > 1; |
| if (hasBaseElementWildcards && multiple != baseMultiple) |
| logError("Could not bind type\"" + schemaType.getName() + |
| "\" because its base type \"" + baseType.getName() + |
| "\" has only one element wildcard and the current type has more.", |
| null, schemaType); |
| } |
| GenericXmlProperty prop = new GenericXmlProperty(); |
| String propName = "_any"; |
| BindingType bType = getWildcardElementBindingType(multiple); |
| prop.setSetterName(MethodName.create("set" + propName, |
| bType.getName().getJavaName())); |
| prop.setGetterName(MethodName.create("get" + propName)); |
| prop.setBindingType(bType); |
| scratch.setAnyElementProperty(prop); |
| } |
| } |
| |
| if (derivationType == SchemaType.DT_RESTRICTION) |
| { |
| // Derivation type is restriction, so no new properties may be added |
| return; |
| } |
| |
| // Handle the attribute wildcards |
| // No check is necessary, because it always maps to the same type if present |
| if (schemaType.hasAttributeWildcards()) { |
| String propName = "_anyAttribute"; |
| GenericXmlProperty prop = new GenericXmlProperty(); |
| BindingType bType = getWildcardAttributeBindingType(); |
| prop.setSetterName(MethodName.create("set" + propName, |
| bType.getName().getJavaName())); |
| prop.setGetterName(MethodName.create("get" + propName)); |
| prop.setBindingType(bType); |
| scratch.setAnyAttributeProperty(prop); |
| } |
| |
| // Now deal with remaining props |
| SchemaProperty[] props = schemaType.getProperties(); |
| for (int i = 0; i < props.length; i++) { |
| QNameProperty prop = (QNameProperty) (props[i].isAttribute() ? seenAttrProps : seenEltProps).get(props[i].getName()); |
| if (prop != null) { |
| // already seen property: verify multiplicity looks cool |
| if (prop.isMultiple() != isMultiple(props[i])) { |
| logError("Could not bind element \"" + props[i].getName() + |
| "\" because the corresponding element in the base type has a " + |
| "different 'maxOccurs' value", null, props[i]); |
| } |
| |
| // todo: think about optionality and nillability too |
| } else { |
| SchemaType sType = props[i].getType(); |
| BindingType bType = bindingTypeForSchemaType(sType); |
| if (bType == null) |
| throw new IllegalStateException("Type " + sType.getName() + |
| "not found in type loader"); |
| |
| String propName = pickUniquePropertyName(props[i].getName(), seenMethodNames); |
| boolean isMultiple = isMultiple(props[i]); |
| JavaTypeName collection = null; |
| |
| prop = new QNameProperty(); |
| prop.setQName(props[i].getName()); |
| prop.setAttribute(props[i].isAttribute()); |
| prop.setNillable(props[i].hasNillable() != SchemaProperty.NEVER); |
| prop.setOptional(isOptional(props[i])); |
| prop.setMultiple(isMultiple); |
| if (prop.isNillable() || prop.isOptional()) |
| bType = findBoxedType(bType); |
| prop.setBindingType(bType); |
| prop.setSetterName(MethodName.create("set" + propName, |
| bType.getName().getJavaName())); |
| prop.setGetterName(MethodName.create("get" + propName)); |
| if (prop.isMultiple()) |
| collection = JavaTypeName.forArray(bType.getName().getJavaName(), 1); |
| prop.setCollectionClass(collection); |
| } |
| scratch.addQNameProperty(prop); |
| } |
| } |
| |
| /** |
| * Resolves a Java array |
| */ |
| private void resolveJavaArray(Scratch scratch) |
| { |
| if (scratch.getCategory() != Scratch.LITERALARRAY_TYPE && |
| scratch.getCategory() != Scratch.LIST_TYPE && |
| scratch.getCategory() != Scratch.SOAPARRAY) |
| return; |
| |
| if (scratch.isStructureResolved()) |
| return; |
| |
| scratch.setStructureResolved(true); |
| |
| BindingType scratchBindingType = scratch.getBindingType(); |
| if (scratchBindingType instanceof WrappedArrayType) { |
| WrappedArrayType bType = (WrappedArrayType) scratchBindingType; |
| JavaTypeName itemName = scratch.getJavaName().getArrayItemType(1); |
| assert(itemName != null); |
| SchemaType sType = getLiteralArrayItemType(scratch.getSchemaType()); |
| assert sType != null : "This was already checked and determined to be non-null"; |
| SchemaProperty prop = scratch.getSchemaType().getProperties()[0]; |
| bType.setItemName(prop.getName()); |
| BindingType itemType = bindingTypeForSchemaType(sType); |
| if (itemType == null) |
| throw new IllegalStateException("Type " + sType.getName() + |
| " not found in type loader"); |
| |
| bType.setItemNillable(prop.hasNillable() != SchemaProperty.NEVER); |
| if (bType.isItemNillable()) |
| itemType = findBoxedType(itemType); |
| bType.setItemType(itemType.getName()); |
| } |
| else if (scratchBindingType instanceof ListArrayType) { |
| ListArrayType bType = (ListArrayType) scratchBindingType; |
| JavaTypeName itemName = scratch.getJavaName().getArrayItemType(1); |
| assert (itemName != null); |
| SchemaType sType = getListItemType(scratch.getSchemaType()); |
| assert (sType != null); |
| BindingType itemType = bindingTypeForSchemaType(sType); |
| if (itemType == null) |
| throw new IllegalStateException("Type " + sType.getName() + |
| " not found in the type loader"); |
| bType.setItemType(itemType.getName()); |
| } |
| else if (scratchBindingType instanceof SoapArrayType) { |
| SoapArrayType bType = (SoapArrayType) scratchBindingType; |
| XmlTypeName typexName = scratch.getXmlName(); |
| XmlTypeName itemxName = typexName.getOuterComponent(); |
| Scratch itemxScratch = scratchForXmlName(itemxName); |
| BindingType itemxType; |
| if (itemxScratch == null) |
| itemxType = mLoader.getBindingType(mLoader.lookupPojoFor(itemxName)); |
| else |
| itemxType = itemxScratch.getBindingType(); |
| // The rule is: if the soap array type looks like a literal array |
| // then the name and nillability are the same as for literal arrays |
| // Otherwise, the name is not significant and nillability is false |
| if (getLiteralArrayItemType(scratch.getSchemaType()) == null) { |
| bType.setItemNillable(false); |
| } |
| else { |
| SchemaProperty prop = scratch.getSchemaType().getProperties()[0]; |
| bType.setItemName(prop.getName()); |
| bType.setItemNillable(prop.hasNillable() != SchemaProperty.NEVER); |
| } |
| |
| if (itemxType != null) { |
| if (bType.isItemNillable()) |
| itemxType = findBoxedType(itemxType); |
| bType.setItemType(itemxType.getName()); |
| } |
| SOAPArrayType aType = getWsdlArrayType(scratch.getSchemaType()); |
| if (aType != null) |
| bType.setRanks(aType.getDimensions().length); |
| |
| return; |
| } |
| else |
| throw new IllegalStateException(); |
| } |
| |
| /** |
| * Resolves a Java enumeration |
| */ |
| private void resolveJavaEnumeration(Scratch scratch) |
| { |
| if (scratch.getCategory() != Scratch.ENUM_TYPE) |
| return; |
| |
| if (scratch.isStructureResolved()) |
| return; |
| |
| scratch.setStructureResolved(true); |
| |
| SchemaType baseType = scratch.getSchemaType().getBaseType(); |
| |
| BindingType bType = bindingTypeForSchemaType(baseType); |
| assert bType != null : "Binding type for schema type \"" + baseType + |
| "\" not found on the mLoader"; |
| |
| JaxrpcEnumType enumType = (JaxrpcEnumType) scratch.getBindingType(); |
| enumType.setFromValueMethod(MethodName.create(JaxrpcEnumType.DEFAULT_FROM_VALUE_NAME, |
| bType.getName().getJavaName())); |
| enumType.setBaseType(bType); |
| } |
| |
| /** |
| * Picks a property name without colliding with names of |
| * previously picked getters and setters. |
| */ |
| private String pickUniquePropertyName(QName name, Set seenMethodNames) { |
| String baseName = NameUtil.upperCamelCase(name.getLocalPart(), mJaxRpcRules); |
| String propName = baseName; |
| for (int i = 1; ; i += 1) { |
| String getter = "get" + propName; |
| String setter = "set" + propName; |
| |
| if (!seenMethodNames.contains(getter) && |
| !seenMethodNames.contains(setter)) { |
| seenMethodNames.add(getter); |
| seenMethodNames.add(setter); |
| return propName; |
| } |
| propName = baseName + i; |
| } |
| } |
| |
| /** |
| * True if the given SchemaProperty has maxOccurs > 1 |
| */ |
| private static boolean isMultiple(SchemaProperty prop) { |
| return (prop.getMaxOccurs() == null || prop.getMaxOccurs().compareTo(BigInteger.ONE) > 0); |
| } |
| |
| /** |
| * True if the given SchemaProperty has minOccurs < 1 and maxOccurs <= 1 |
| */ |
| private static boolean isOptional(SchemaProperty prop) { |
| return (prop.getMinOccurs().signum() == 0 && !isMultiple(prop)); |
| } |
| |
| /** |
| * Returns a collection of QNameProperties for a given schema type that |
| * may either be on the mLoader or the current scratch area. |
| */ |
| private Collection extractProperties(SchemaType sType) { |
| // case 1: it's in the current area |
| Scratch scratch = scratchForSchemaType(sType); |
| if (scratch != null) { |
| // The type found may not be a structure |
| if (scratch.getCategory() == Scratch.STRUCT_TYPE) { |
| resolveJavaStructure(scratch); |
| return scratch.getQNameProperties(); |
| } |
| else |
| return null; |
| } |
| |
| // case 2: it's in the mLoader |
| BindingType bType = mLoader.getBindingType(mLoader.lookupPojoFor(XmlTypeName.forSchemaType(sType))); |
| |
| Collection result = new ArrayList(); |
| if (bType instanceof ByNameBean) { |
| ByNameBean bnb = (ByNameBean) bType; |
| for (Iterator i = bnb.getProperties().iterator(); i.hasNext();) { |
| result.add(i.next()); |
| } |
| } |
| else if (bType instanceof SimpleContentBean) { |
| SimpleContentBean scb = (SimpleContentBean) bType; |
| for (Iterator i = scb.getAttributeProperties().iterator(); i.hasNext();) { |
| result.add(i.next()); |
| } |
| } |
| else |
| return null; |
| |
| return result; |
| } |
| |
| /** |
| * Returns the simple type which the base of a complex Type with simpleContent |
| */ |
| private BindingType extractBindingType(SchemaType sType) { |
| // case 1: it's in the current area |
| Scratch scratch = scratchForSchemaType(sType); |
| if (scratch != null) |
| return scratch.getBindingType(); |
| |
| // case 2: it's in the mLoader |
| BindingType bType = mLoader.getBindingType(mLoader.lookupPojoFor(XmlTypeName. |
| forSchemaType(sType))); |
| |
| return bType; |
| } |
| |
| /** |
| * Returns a BindingType representing the default type for <xs:any> content |
| */ |
| private BindingType getWildcardElementBindingType(boolean multiple) { |
| JavaTypeName javaName; |
| javaName = JavaTypeName.forString(WILDCARD_ELEMENT_MAPPING); |
| if (multiple) |
| javaName = JavaTypeName.forArray(javaName, 1); |
| XmlTypeName xmlName = XmlTypeName.forTypeNamed(new QName(xsns, "anyType")); |
| return new SimpleBindingType(BindingTypeName.forPair(javaName, xmlName)); |
| } |
| |
| /** |
| * Returns a BindingType representing the default type for <xs:anyAttribute> |
| */ |
| private BindingType getWildcardAttributeBindingType() { |
| JavaTypeName javaName; |
| javaName = JavaTypeName.forString(WILDCARD_ATTRIBUTE_MAPPING); |
| XmlTypeName xmlName = XmlTypeName.forTypeNamed(new QName(xsns, "anyType")); |
| return new SimpleBindingType(BindingTypeName.forPair(javaName, xmlName)); |
| } |
| |
| private JavaTypeName getBoxedName(JavaTypeName jName) |
| { |
| // We could use a map here and initialize it on first use |
| for (int i = 0; i < PRIMITIVE_TYPES.length; i++) |
| if (PRIMITIVE_TYPES[i].equals(jName.toString())) |
| return JavaTypeName.forString(BOXED_TYPES[i]); |
| |
| return null; |
| } |
| |
| /** |
| * Returns the boxed version of the given binding type |
| */ |
| private BindingType findBoxedType(BindingType type) |
| { |
| BindingTypeName btName = type.getName(); |
| JavaTypeName javaName = btName.getJavaName(); |
| BindingType result = null; |
| JavaTypeName boxedJavaName = getBoxedName(javaName); |
| if (boxedJavaName != null) |
| { |
| // This is a primitive type |
| BindingTypeName boxedName = BindingTypeName.forPair(boxedJavaName, btName.getXmlName()); |
| // If the type is in the current scratch area, create a new boxed type |
| if (scratchForXmlName(btName.getXmlName()) != null) |
| { |
| result = bindingFile.getBindingType(boxedName); |
| if (result == null) |
| { |
| result = changeJavaName((SimpleBindingType) type, boxedName); |
| bindingFile.addBindingType(result, false, false); |
| } |
| return result; |
| } |
| // If this is a type available on the mLoader, try to locate |
| // the boxed type corresponding to it. |
| result = mLoader.getBindingType(boxedName); |
| if (result != null) |
| return result; |
| |
| // Type is not in the current scratch area nor on the mLoader |
| // We create it and add it to the file |
| result = bindingFile.getBindingType(boxedName); |
| if (result == null) |
| { |
| result = changeJavaName((SimpleBindingType) type, boxedName); |
| bindingFile.addBindingType(result, false, false); |
| } |
| return result; |
| } |
| |
| return type; |
| } |
| |
| /** |
| * Creates a new binding type based on the given binding type and bearing the |
| * new JavaTypeName. This is necessary to created boxed versions of |
| * binding types based on Java primitive types. |
| */ |
| private BindingType changeJavaName(SimpleBindingType bType, BindingTypeName btName) |
| { |
| SimpleBindingType result = new SimpleBindingType(btName); |
| result.setAsIfXmlType(bType.getAsIfXmlType()); |
| result.setWhitespace(bType.getWhitespace()); |
| return result; |
| } |
| |
| /** |
| * True for a schema type that is a SOAP array. |
| */ |
| private static boolean isSoapArray(SchemaType sType) { |
| // SOAP Array definition must be put on the compiletime classpath |
| while (sType != null) { |
| String signature = XmlTypeName.forSchemaType(sType).toString(); |
| |
| // captures both SOAP 1.1 and SOAP 1.2+ |
| if (signature.equals("t=Array@http://schemas.xmlsoap.org/soap/encoding/") || |
| signature.startsWith("t=Array@http://www.w3.org/") |
| && signature.endsWith("/soap-encoding")) |
| return true; |
| sType = sType.getBaseType(); |
| } |
| return false; |
| } |
| |
| private static final QName arrayType = new QName("http://schemas.xmlsoap.org/soap/encoding/", "arrayType"); |
| |
| /** |
| * Returns an XmlTypeName describing a SOAP array. |
| */ |
| private static XmlTypeName soapArrayTypeName(SchemaType sType) { |
| // first, look for wsdl:arrayType default - this will help us with multidimensional arrays |
| SOAPArrayType defaultArrayType = getWsdlArrayType(sType); |
| |
| // method 1: trust wsdl:arrayType |
| if (defaultArrayType != null) |
| return XmlTypeName.forSoapArrayType(defaultArrayType); |
| |
| // method 2: SOAP 1.2 equivalent? |
| // todo: track what do WSDLs do in the world of SOAP 1.2. |
| |
| // method 3: look at the type of a unique element. |
| SchemaType itemType = XmlObject.type; |
| SchemaProperty[] props = sType.getElementProperties(); |
| if (props.length == 1) |
| itemType = props[0].getType(); |
| |
| return XmlTypeName.forNestedNumber(XmlTypeName.SOAP_ARRAY, 1, XmlTypeName.forSchemaType(itemType)); |
| } |
| |
| private static SOAPArrayType getWsdlArrayType(SchemaType sType) { |
| SchemaLocalAttribute attr = sType.getAttributeModel().getAttribute(arrayType); |
| if (attr != null) |
| return ((SchemaWSDLArrayType) attr).getWSDLArrayType(); |
| return null; |
| } |
| |
| /** |
| * Climbs the structure of a schema type to find the namespace within |
| * which it was defined. |
| */ |
| private String findContainingNamespace(SchemaType sType) { |
| for (; ;) { |
| if (sType.isDocumentType()) |
| return sType.getDocumentElementName().getNamespaceURI(); |
| else if (sType.isAttributeType()) |
| return sType.getAttributeTypeAttributeName().getNamespaceURI(); |
| else if (sType.getName() != null) |
| return sType.getName().getNamespaceURI(); |
| sType = sType.getOuterType(); |
| } |
| } |
| |
| /** |
| * Searches the content of a complex type to see if more than one <xs:any> |
| * wildcard was defined |
| */ |
| private int countWildcards(SchemaParticle p) |
| { |
| int totalWildcards = 0; |
| switch (p.getParticleType()) { |
| case SchemaParticle.ALL: |
| case SchemaParticle.SEQUENCE: |
| { |
| SchemaParticle[] children = p.getParticleChildren(); |
| for (int i = 0; i < children.length; i++) |
| totalWildcards += countWildcards(children[i]); |
| } |
| break; |
| case SchemaParticle.CHOICE: |
| { |
| SchemaParticle[] children = p.getParticleChildren(); |
| for (int i = 0; i < children.length; i++) { |
| int n = countWildcards(children[i]); |
| if (n > totalWildcards) |
| totalWildcards = n; |
| } |
| } |
| break; |
| case SchemaParticle.ELEMENT: |
| break; |
| case SchemaParticle.WILDCARD: |
| totalWildcards = p.getIntMaxOccurs(); |
| break; |
| } |
| return totalWildcards; |
| } |
| |
| /** |
| * Picks a unique fully-qualified Java class name for the given schema |
| * type. Uses and updates the "usedNames" set. |
| */ |
| private JavaTypeName pickUniqueJavaName(SchemaType sType, boolean isEnum) { |
| String baseName = getDefaultJavaName(sType); |
| |
| if (duplicateNames.contains(baseName.toLowerCase())) |
| { |
| if (isEnum) |
| baseName = baseName + "_Enumeration"; |
| else if (sType.getContainerField() != null && |
| !sType.getContainerField().isAttribute()) |
| baseName = baseName + "_Element"; |
| else if (sType.getName() != null) |
| baseName = baseName + "_Type"; |
| } |
| String pickedName = baseName; |
| |
| for (int i = 1; usedNames.contains(pickedName.toLowerCase()); i += 1) |
| pickedName = baseName + i; |
| |
| usedNames.add(pickedName.toLowerCase()); |
| |
| return JavaTypeName.forString(pickedName); |
| } |
| |
| private String getDefaultJavaName(SchemaType sType) { |
| QName qname = null; |
| while (qname == null) { |
| if (sType.isDocumentType()) |
| qname = sType.getDocumentElementName(); |
| else if (sType.isAttributeType()) |
| qname = sType.getAttributeTypeAttributeName(); |
| else if (sType.getName() != null) |
| qname = sType.getName(); |
| else if (sType.getContainerField() != null) { |
| qname = sType.getContainerField().getName(); |
| if (qname.getNamespaceURI().length() == 0) |
| qname = new QName(findContainingNamespace(sType), qname.getLocalPart()); |
| } |
| sType = sType.getOuterType(); |
| } |
| |
| return NameUtil.getClassNameFromQName(qname, mJaxRpcRules); |
| } |
| |
| /** |
| * Resolves an atomic scratch all at once, including its |
| * JavaTypeName and basedOn fields. |
| * |
| * This resolution method sets up a scratch so that is |
| * is "based on" another binding type. It finds the |
| * underlying binding type by climing the base type |
| * chain, and grabbing the first hit. |
| */ |
| private void resolveSimpleScratch(Scratch scratch) { |
| assert(scratch.getCategory() == Scratch.ATOMIC_TYPE); |
| logVerbose("resolveSimpleScratch "+scratch.getXmlName()); |
| if (scratch.getJavaName() != null) |
| return; |
| |
| SchemaType baseType = scratch.getSchemaType().getBaseType(); |
| while (baseType != null) { |
| // find a base type within this type system |
| Scratch basedOnScratch = scratchForSchemaType(baseType); |
| if (basedOnScratch != null) { |
| if (basedOnScratch.getCategory() != Scratch.ATOMIC_TYPE) |
| throw new IllegalStateException("Atomic types should only inherit from atomic types"); |
| resolveSimpleScratch(basedOnScratch); |
| scratch.setJavaName(basedOnScratch.getJavaName()); |
| scratch.setAsIf(basedOnScratch.getXmlName()); |
| return; |
| } |
| |
| // or if not within this type system, find the base type on the mLoader |
| XmlTypeName treatAs = XmlTypeName.forSchemaType(baseType); |
| BindingType basedOnBinding = mLoader.getBindingType(mLoader.lookupPojoFor(treatAs)); |
| if (basedOnBinding != null) { |
| scratch.setJavaName(basedOnBinding.getName().getJavaName()); |
| scratch.setAsIf(treatAs); |
| return; |
| } |
| |
| // or go to the next base type up |
| baseType = baseType.getBaseType(); |
| } |
| |
| // builtin at least should give us xs:anyType |
| throw new IllegalStateException("Builtin binding type loader is not on mLoader."); |
| } |
| |
| /** |
| * Searches on the mLoader for the given schema type and |
| * returns the java name of the type found or errors |
| * if it cannot find the type |
| */ |
| private JavaTypeName getTypeNameFromLoader(SchemaType sType) { |
| return getTypeNameFromLoader(XmlTypeName.forSchemaType(sType)); |
| } |
| |
| private JavaTypeName getTypeNameFromLoader(XmlTypeName typeName) { |
| BindingType bType = mLoader.getBindingType(mLoader. |
| lookupPojoFor(typeName)); |
| if (bType != null) |
| return bType.getName().getJavaName(); |
| |
| return null; |
| } |
| |
| /** |
| * Looks on both the mLoader and in the current scratch area for |
| * the binding type corresponding to the given schema type. Must |
| * be called after all the binding types have been created. |
| */ |
| private BindingType bindingTypeForSchemaType(SchemaType sType) { |
| Scratch scratch = scratchForSchemaType(sType); |
| if (scratch != null) |
| return scratch.getBindingType(); |
| return mLoader.getBindingType(mLoader.lookupPojoFor(XmlTypeName.forSchemaType(sType))); |
| } |
| |
| /** |
| * Returns the scratch area for a given schema type. Notice that |
| * SOAP arrays have an XmlTypeName but not a schema type. |
| */ |
| private Scratch scratchForSchemaType(SchemaType sType) { |
| return (Scratch) scratchFromSchemaType.get(sType); |
| } |
| |
| /** |
| * Returns the scratch area for a given XmlTypeName. |
| */ |
| private Scratch scratchForXmlName(XmlTypeName xmlName) { |
| return (Scratch) scratchFromXmlName.get(xmlName); |
| } |
| |
| /** |
| * Returns the scratch area for a given JavaTypeName. Notice that only |
| * structures generate a java class, so not non-strucuture scratch areas |
| * cannot be referenced this way. |
| */ |
| private Scratch scratchForJavaNameString(String javaName) { |
| return (Scratch) scratchFromJavaNameString.get(javaName); |
| } |
| |
| /** |
| * Extracts the schema type for the array items for a literal array. |
| */ |
| private static SchemaType getLiteralArrayItemType(SchemaType sType) { |
| // consider: must the type be named "ArrayOf..."? |
| |
| if (sType.isSimpleType() || sType.getContentType() == SchemaType.SIMPLE_CONTENT) |
| return null; |
| SchemaProperty[] prop = sType.getProperties(); |
| if (prop.length != 1 || prop[0].isAttribute()) |
| return null; |
| BigInteger max = prop[0].getMaxOccurs(); |
| if (max != null && max.compareTo(BigInteger.ONE) <= 0) |
| return null; |
| return prop[0].getType(); |
| } |
| |
| private static SchemaType getListItemType(SchemaType sType) { |
| return sType.getListItemType(); |
| } |
| |
| /** |
| * True if the given schema type is interpreted as a .NET-style |
| * array. |
| */ |
| private static boolean isLiteralArray(SchemaType sType) { |
| return getLiteralArrayItemType(sType) != null; |
| } |
| |
| /** |
| * True if the given schema type is an enumeration type. |
| */ |
| private static boolean isEnumeration(SchemaType sType) { |
| return sType.getEnumerationValues() != null; |
| } |
| |
| /** |
| * True if the given schema type is a list type |
| */ |
| private static boolean isList(SchemaType sType) { |
| return getListItemType(sType) != null; |
| } |
| |
| /** |
| * Scratch area corresponding to a schema type, used for the binding |
| * computation. |
| */ |
| private static class Scratch { |
| Scratch(SchemaType schemaType, XmlTypeName xmlName, int category) { |
| this.schemaType = schemaType; |
| this.xmlName = xmlName; |
| this.category = category; |
| } |
| |
| private BindingType bindingType; |
| private SchemaType schemaType; // may be null |
| private JavaTypeName javaName; |
| private XmlTypeName xmlName; |
| |
| private int category; |
| |
| // atomic types get a treatAs |
| private XmlTypeName asIf; |
| private boolean isStructureResolved; |
| |
| // categories of Scratch, established at ctor time |
| public static final int ATOMIC_TYPE = 1; |
| public static final int STRUCT_TYPE = 2; |
| public static final int ENUM_TYPE = 3; |
| public static final int LIST_TYPE = 4; |
| public static final int LITERALARRAY_TYPE = 5; |
| public static final int SOAPARRAY_REF = 6; |
| public static final int SOAPARRAY = 7; |
| public static final int ELEMENT = 8; |
| public static final int ATTRIBUTE = 9; |
| |
| public int getCategory() { |
| return category; |
| } |
| |
| public JavaTypeName getJavaName() { |
| return javaName; |
| } |
| |
| public void setJavaName(JavaTypeName javaName) { |
| this.javaName = javaName; |
| } |
| |
| public BindingType getBindingType() { |
| return bindingType; |
| } |
| |
| public void setBindingType(BindingType bindingType) { |
| this.bindingType = bindingType; |
| } |
| |
| public SchemaType getSchemaType() { |
| return schemaType; |
| } |
| |
| public XmlTypeName getXmlName() { |
| return xmlName; |
| } |
| |
| public void setXmlName(XmlTypeName xmlName) { |
| this.xmlName = xmlName; |
| } |
| |
| public XmlTypeName getAsIf() { |
| return asIf; |
| } |
| |
| public void setAsIf(XmlTypeName xmlName) { |
| this.asIf = xmlName; |
| } |
| |
| public void addQNameProperty(QNameProperty prop) { |
| if (bindingType instanceof ByNameBean) |
| ((ByNameBean) bindingType).addProperty(prop); |
| else if (bindingType instanceof SimpleContentBean) |
| ((SimpleContentBean) bindingType).addProperty(prop); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public Collection getQNameProperties() { |
| if (bindingType instanceof ByNameBean) |
| return ((ByNameBean) bindingType).getProperties(); |
| else if (bindingType instanceof SimpleContentBean) |
| return ((SimpleContentBean) bindingType).getAttributeProperties(); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public void setSimpleContentProperty(SimpleContentProperty prop) { |
| if (bindingType instanceof SimpleContentBean) |
| ((SimpleContentBean) bindingType).setSimpleContentProperty(prop); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public SimpleContentProperty getSimpleContentProperty() { |
| if (bindingType instanceof SimpleContentBean) |
| return ((SimpleContentBean) bindingType).getSimpleContentProperty(); |
| else |
| return null; |
| } |
| |
| public void setAnyAttributeProperty(GenericXmlProperty prop) { |
| if (bindingType instanceof ByNameBean) |
| ((ByNameBean) bindingType).setAnyAttributeProperty(prop); |
| else if (bindingType instanceof SimpleContentBean) |
| ((SimpleContentBean) bindingType).setAnyAttributeProperty(prop); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public GenericXmlProperty getAnyAttributeProperty() { |
| if (bindingType instanceof ByNameBean) |
| return ((ByNameBean) bindingType).getAnyAttributeProperty(); |
| else if (bindingType instanceof SimpleContentBean) |
| return ((SimpleContentBean) bindingType).getAnyAttributeProperty(); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public void setAnyElementProperty(GenericXmlProperty prop) { |
| if (bindingType instanceof ByNameBean) |
| ((ByNameBean) bindingType).setAnyElementProperty(prop); |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public GenericXmlProperty getAnyElementProperty() { |
| if (bindingType instanceof ByNameBean) |
| return ((ByNameBean) bindingType).getAnyElementProperty(); |
| else if (bindingType instanceof SimpleContentBean) |
| return null; |
| else |
| throw new IllegalStateException(); |
| } |
| |
| public boolean isStructureResolved() { |
| return this.isStructureResolved; |
| } |
| |
| public void setStructureResolved(boolean isStructureResolved) { |
| this.isStructureResolved = isStructureResolved; |
| } |
| |
| public String toString() { |
| return getJavaName()+"<->"+getXmlName(); |
| } |
| } |
| |
| /** |
| * Returns an iterator for all the Scratch's |
| */ |
| private Iterator scratchIterator() { |
| return scratchFromXmlName.values().iterator(); |
| } |
| |
| /** |
| * Returns an iterator for all the schema types |
| */ |
| private Iterator allTypeIterator() { |
| class AllTypeIterator implements Iterator { |
| int index; |
| List allSeenTypes; |
| |
| AllTypeIterator(SchemaTypeSystem sts) { |
| allSeenTypes = new ArrayList(); |
| allSeenTypes.addAll(Arrays.asList(sts.documentTypes())); |
| allSeenTypes.addAll(Arrays.asList(sts.attributeTypes())); |
| allSeenTypes.addAll(Arrays.asList(sts.globalTypes())); |
| // allSeenTypes.addAll(Arrays.asList(XmlBeans.getBuiltinTypeSystem().globalTypes())); |
| index = 0; |
| } |
| |
| public boolean hasNext() { |
| return index < allSeenTypes.size(); |
| } |
| |
| public Object next() { |
| SchemaType next = (SchemaType) allSeenTypes.get(index); |
| allSeenTypes.addAll(Arrays.asList(next.getAnonymousTypes())); |
| index += 1; |
| return next; |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| |
| return new AllTypeIterator(sts); |
| } |
| |
| /** |
| * Iterates over all the top-level Java class names generated |
| * by this binding. Used by getToplevelClasses. |
| */ |
| private class TopLevelClassNameIterator implements Iterator { |
| private final Iterator si = scratchIterator(); |
| private Scratch next = nextStructure(); |
| |
| public boolean hasNext() { |
| return next != null; |
| } |
| |
| public Object next() { |
| // todo: need to strip off x= from xmlobject name |
| String result = next.getJavaName().toString(); |
| next = nextStructure(); |
| return result; |
| } |
| |
| private Scratch nextStructure() { |
| while (si.hasNext()) { |
| Scratch scratch = (Scratch) si.next(); |
| if (scratch.getCategory() == Scratch.STRUCT_TYPE || |
| scratch.getCategory() == Scratch.ENUM_TYPE) |
| return scratch; |
| } |
| return null; |
| } |
| |
| public void remove() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| } |
| |
| // ======================================================================== |
| // Java Codegen methods |
| // |
| // REVIEW it may be worth factoring these methods back out into a separate |
| // class someday. Somebody conceivably might want to plug in here (at their |
| // own risk, of course). pcal 12/12/03 |
| |
| private void writeJavaFiles() { |
| Collection classnames = getToplevelClasses(); |
| for (Iterator i = classnames.iterator(); i.hasNext();) { |
| String className = (String) i.next(); |
| printSourceCode(className); |
| } |
| } |
| |
| /** |
| * Returns a collection of fully-qualified Java class name strings |
| * generated by this binding. |
| */ |
| public Collection getToplevelClasses() { |
| return new AbstractCollection() { |
| public Iterator iterator() { |
| return new TopLevelClassNameIterator(); |
| } |
| |
| public int size() { |
| return structureCount; |
| } |
| }; |
| } |
| |
| /** |
| * Prints the Java source code for the given generated java class name. |
| */ |
| private void printSourceCode(String topLevelClassName) { |
| Scratch scratch = scratchForJavaNameString(topLevelClassName); |
| if (scratch == null) { |
| logError("Could not find scratch for " + topLevelClassName); //? |
| return; |
| } |
| try { |
| printClass(scratch); |
| } catch (IOException ioe) { |
| logError(ioe); |
| } |
| } |
| |
| /** |
| * Prints out a java class for the schema struct represented by the given |
| * Scratch object. |
| * |
| */ |
| private void printClass(Scratch scratch) throws IOException { |
| assert(scratch.getCategory() == Scratch.STRUCT_TYPE || |
| scratch.getCategory() == Scratch.ENUM_TYPE); |
| JavaTypeName javaName = scratch.getJavaName(); |
| |
| String packageName = javaName.getPackage(); |
| String shortClassName = javaName.getShortClassName(); |
| BindingType baseType = null; |
| SchemaType bSchemaType = scratch.getSchemaType().getBaseType(); |
| if (!bSchemaType.isSimpleType()) |
| baseType = bindingTypeForSchemaType(bSchemaType); |
| String baseJavaname = null; |
| if (baseType != null) { |
| baseJavaname = baseType.getName().getJavaName().toString(); |
| if (baseJavaname.equals("java.lang.Object")) |
| baseJavaname = null; |
| } |
| // begin writing class |
| mJoust.startFile(packageName, shortClassName); |
| mJoust.writeComment("Generated from schema type " + scratch.getXmlName()); |
| |
| if (scratch.getCategory() == Scratch.STRUCT_TYPE) |
| printJavaStruct(scratch, baseJavaname); |
| else |
| printJavaEnum(scratch, baseJavaname); |
| |
| mJoust.endFile(); |
| } |
| |
| private void printJavaStruct(Scratch scratch, String baseJavaName) throws IOException { |
| mJoust.startClass(Modifier.PUBLIC, baseJavaName, null); |
| Set seenFieldNames = new HashSet(); |
| // Write out the special "_value" property, if needed |
| SimpleContentProperty scprop = scratch.getSimpleContentProperty(); |
| if (scprop != null) { |
| String fieldName = pickUniqueFieldName(scprop.getGetterName().getSimpleName(), |
| seenFieldNames); |
| JavaTypeName jType = scprop.getTypeName().getJavaName(); |
| addJavaBeanProperty(fieldName, jType.toString(), |
| scprop.getGetterName().getSimpleName(), scprop.getSetterName().getSimpleName()); |
| } |
| |
| // Write out the Generic Xml properties, if needed |
| GenericXmlProperty gxprop = scratch.getAnyElementProperty(); |
| if (gxprop != null) { |
| String fieldName = pickUniqueFieldName(gxprop.getGetterName().getSimpleName(), |
| seenFieldNames); |
| JavaTypeName jType = gxprop.getTypeName().getJavaName(); |
| addJavaBeanProperty(fieldName, jType.toString(), |
| gxprop.getGetterName().getSimpleName(), gxprop.getSetterName().getSimpleName()); |
| } |
| gxprop = scratch.getAnyAttributeProperty(); |
| if (gxprop != null) { |
| String fieldName = pickUniqueFieldName(gxprop.getGetterName().getSimpleName(), |
| seenFieldNames); |
| JavaTypeName jType = gxprop.getTypeName().getJavaName(); |
| addJavaBeanProperty(fieldName, jType.toString(), |
| gxprop.getGetterName().getSimpleName(), gxprop.getSetterName().getSimpleName()); |
| } |
| |
| Collection props = scratch.getQNameProperties(); |
| Map fieldNames = new HashMap(); |
| |
| // pick field names |
| for (Iterator i = props.iterator(); i.hasNext();) { |
| QNameProperty prop = (QNameProperty) i.next(); |
| fieldNames.put(prop, pickUniqueFieldName(prop.getGetterName().getSimpleName(), |
| seenFieldNames)); |
| } |
| |
| // print fields, getters, and setters |
| for (Iterator i = props.iterator(); i.hasNext();) { |
| QNameProperty prop = (QNameProperty) i.next(); |
| JavaTypeName jType = prop.getTypeName().getJavaName(); |
| |
| if (prop.getCollectionClass() != null) { |
| jType = prop.getCollectionClass(); |
| } |
| String fieldName = (String) fieldNames.get(prop); |
| addJavaBeanProperty(fieldName, jType.toString(), |
| prop.getGetterName().getSimpleName(), prop.getSetterName().getSimpleName()); |
| } |
| mJoust.endClassOrInterface(); |
| } |
| |
| private void addJavaBeanProperty(String name, String type, String getter, String setter) |
| throws IOException { |
| // declare the field |
| Variable propertyField = |
| mJoust.writeField(Modifier.PRIVATE, |
| type, |
| name, |
| null); |
| //write getter |
| mJoust.startMethod(Modifier.PUBLIC, |
| type, |
| getter, |
| null, null, null); |
| mJoust.writeReturnStatement(propertyField); |
| mJoust.endMethodOrConstructor(); |
| //write setter |
| Variable[] params = mJoust.startMethod(Modifier.PUBLIC, |
| "void", |
| setter, |
| new String[]{type}, |
| new String[]{name}, |
| null); |
| mJoust.writeAssignmentStatement(propertyField, params[0]); |
| mJoust.endMethodOrConstructor(); |
| } |
| |
| private void printJavaEnum(Scratch scratch, String baseJavaName) throws IOException { |
| Set seenFieldNames = new HashSet(); |
| XmlAnySimpleType[] enumValues = scratch.getSchemaType().getEnumerationValues(); |
| JaxrpcEnumType enumType = (JaxrpcEnumType) scratch.getBindingType(); |
| JavaTypeName baseType = enumType.getBaseTypeName().getJavaName(); |
| EnumerationPrintHelper enumHelper = |
| new EnumerationPrintHelper(baseType, mJoust.getExpressionFactory(), |
| scratch.getSchemaType()); |
| |
| // figure out what import statements we need |
| boolean useArrays = enumHelper.isArray() || enumHelper.isBinary(); |
| if (useArrays) { |
| mJoust.writeImportStatement("java.util.Arrays"); |
| } |
| mJoust.writeImportStatement("java.util.HashMap"); |
| mJoust.writeImportStatement("java.util.Map"); |
| if (enumHelper.isArray()) { |
| mJoust.writeImportStatement("java.util.StringTokenizer"); |
| } |
| mJoust.writeImportStatement("org.apache.xmlbeans.impl.util.XsTypeConverter"); |
| mJoust.startClass(Modifier.PUBLIC, baseJavaName, null); |
| |
| // Assign appropriate names to the fields we use |
| boolean matchOk = true; |
| String[] fieldNames = new String[enumValues.length]; |
| String instanceVarName = "value"; |
| String instanceMapName = "map"; |
| boolean isQName = enumValues.length > 0 && enumValues[0] instanceof XmlQName; |
| for (int i = 0; i < enumValues.length; i++) { |
| String tentativeName = NameUtil.lowerCamelCase(isQName ? |
| ((XmlQName) enumValues[i]).getQNameValue().getLocalPart() : |
| enumValues[i].getStringValue(), |
| true, false); |
| if (!NameUtil.isValidJavaIdentifier(tentativeName)) { |
| matchOk = false; |
| break; |
| } |
| if (seenFieldNames.contains(tentativeName)) { |
| matchOk = false; |
| break; |
| } |
| // If we got here, we found a suitable name for this constant |
| seenFieldNames.add(tentativeName); |
| fieldNames[i] = tentativeName; |
| } |
| if (!matchOk) { |
| // One or more values could not map to a valid Java identifier |
| // As per JAX-RPC, rename all identifiers to 'value1', 'value2', etc |
| for (int i = 0; i < enumValues.length; i++) { |
| String name = "value" + (i + 1); |
| fieldNames[i] = name; |
| } |
| } |
| else { |
| // Check if the instance var name collides with any of the constants |
| while (seenFieldNames.contains(instanceVarName)) |
| instanceVarName = "x" + instanceVarName; |
| // Check the map var name |
| while (seenFieldNames.contains(instanceMapName)) |
| instanceMapName = "x" + instanceMapName; |
| } |
| |
| // We have the names, generate the class! |
| // ====================================== |
| // Private fields and constructor |
| Variable instanceVar = |
| mJoust.writeField(Modifier.PRIVATE, |
| baseType.toString(), |
| instanceVarName, |
| null); |
| Variable instanceMap = |
| mJoust.writeField(Modifier.PRIVATE | Modifier.STATIC, |
| "Map", |
| instanceMapName, |
| mJoust.getExpressionFactory().createVerbatim("new HashMap()")); |
| Variable[] params = mJoust.startConstructor(Modifier.PROTECTED, |
| new String[] {baseType.toString()}, |
| new String[] {"value"}, |
| null); |
| mJoust.writeAssignmentStatement(instanceVar, params[0]); |
| mJoust.endMethodOrConstructor(); |
| Variable[] constants = new Variable[enumValues.length]; |
| |
| // Constants of the enumeration base type |
| for (int i = 0; i < enumValues.length; i++) { |
| XmlAnySimpleType enumValue = enumValues[i]; |
| constants[i] = |
| mJoust.writeField(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, |
| baseType.toString(), |
| "_" + fieldNames[i], |
| enumHelper.getInitExpr(enumValue)); |
| } |
| |
| // Constants of enumeration type |
| String shortClassName = scratch.getJavaName().getShortClassName(); |
| for (int i = 0; i < enumValues.length; i++) { |
| mJoust.writeField(Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL, |
| shortClassName, |
| fieldNames[i], |
| mJoust.getExpressionFactory().createVerbatim("new " + shortClassName + "(_" + fieldNames[i] + ")")); |
| } |
| |
| // Implementation of the getValue() method |
| mJoust.startMethod(Modifier.PUBLIC, |
| baseType.toString(), |
| enumType.getGetValueMethod().getSimpleName(), |
| null, null, null); |
| mJoust.writeReturnStatement(instanceVar); |
| mJoust.endMethodOrConstructor(); |
| |
| // Implementation of the fromValue() method |
| mJoust.startMethod(Modifier.PUBLIC | Modifier.STATIC, |
| shortClassName, |
| enumType.getFromValueMethod().getSimpleName(), |
| new String[] {baseType.toString()}, |
| new String[] {"value"}, |
| null); |
| String valueVarName = "value"; |
| if (useArrays) { |
| mJoust.writeStatement(shortClassName + " new" + valueVarName + " = new " + |
| shortClassName + "(" + valueVarName + ")"); |
| valueVarName = "new" + valueVarName; |
| } |
| mJoust.writeStatement("if (" + instanceMapName + ".containsKey(" + |
| (useArrays ? valueVarName : enumHelper.getObjectVersion("value")) + |
| ")) return (" + shortClassName + ") " + |
| instanceMapName + ".get(" + |
| (useArrays ? valueVarName : enumHelper.getObjectVersion("value")) |
| + ")"); |
| mJoust.writeStatement("else throw new IllegalArgumentException()"); |
| mJoust.endMethodOrConstructor(); |
| |
| // Implementation of the fromString() method |
| params = mJoust.startMethod(Modifier.PUBLIC | Modifier.STATIC, |
| shortClassName, |
| enumType.getFromStringMethod().getSimpleName(), |
| new String[] {"String"}, |
| new String[] {"value"}, |
| null); |
| if (enumHelper.isArray()) { |
| // Here we have to tokenize the input string, then build up an array |
| // of the enumeration's type and then call fromValue() |
| final String STRING_PARTS = "parts"; |
| final String BASETYPE_ARRAY = "array"; |
| mJoust.writeStatement("String[] " + STRING_PARTS + |
| "= org.apache.xmlbeans.impl.values.XmlListImpl.split_list(value)"); |
| mJoust.writeStatement(baseType.toString() + " " + BASETYPE_ARRAY + " = new " + |
| baseType.getArrayItemType(baseType.getArrayDepth()).toString() + |
| "[" + STRING_PARTS + ".length" + "]" + baseType.getArrayString(1)); |
| mJoust.writeStatement("for (int i = 0; i < " + BASETYPE_ARRAY + ".length; i++) " + |
| BASETYPE_ARRAY + "[i] = " + |
| enumHelper.getFromStringExpr(mJoust.getExpressionFactory().createVerbatim( |
| STRING_PARTS + "[i]")).getMemento().toString()); |
| mJoust.writeReturnStatement(mJoust.getExpressionFactory().createVerbatim( |
| enumType.getFromValueMethod().getSimpleName() + "(" + BASETYPE_ARRAY + ")")); |
| } |
| else |
| { |
| mJoust.writeReturnStatement(mJoust.getExpressionFactory().createVerbatim( |
| enumType.getFromValueMethod().getSimpleName() + "(" + |
| enumHelper.getFromStringExpr(params[0]).getMemento().toString() + |
| ")")); |
| } |
| mJoust.endMethodOrConstructor(); |
| |
| // Implementation of the toXml() method |
| mJoust.startMethod(Modifier.PUBLIC, |
| "String", |
| enumType.getToXMLMethod().getSimpleName(), |
| null, null, null); |
| if (enumHelper.isArray()) { |
| final String STRING_LIST = "list"; |
| mJoust.writeStatement("StringBuffer " + STRING_LIST + " = new StringBuffer()"); |
| mJoust.writeStatement("for (int i = 0; i < " + instanceVarName + ".length; i++) " + |
| STRING_LIST + ".append(" + enumHelper.getToXmlString(instanceVar, "i") + |
| ").append(' ')"); |
| mJoust.writeReturnStatement(mJoust.getExpressionFactory().createVerbatim(STRING_LIST + ".toString()")); |
| } |
| else { |
| mJoust.writeReturnStatement(enumHelper.getToXmlExpr(instanceVar)); |
| } |
| mJoust.endMethodOrConstructor(); |
| |
| // Implementation of the toString() method |
| mJoust.startMethod(Modifier.PUBLIC, |
| "String", |
| "toString", |
| null, null, null); |
| if (enumHelper.isArray()) { |
| final String STRING_LIST = "list"; |
| mJoust.writeStatement("StringBuffer " + STRING_LIST + " = new StringBuffer()"); |
| mJoust.writeStatement("for (int i = 0; i < " + instanceVarName + ".length; i++) " + |
| STRING_LIST + ".append(String.valueOf(" + |
| instanceVarName + "[i]" + |
| ")).append(' ')"); |
| mJoust.writeReturnStatement(mJoust.getExpressionFactory().createVerbatim(STRING_LIST + ".toString()")); |
| } |
| else { |
| mJoust.writeReturnStatement(mJoust.getExpressionFactory().createVerbatim( |
| "String.valueOf(" + instanceVarName + ")")); |
| } |
| mJoust.endMethodOrConstructor(); |
| |
| // Implementation of the equals() method |
| params = mJoust.startMethod(Modifier.PUBLIC, |
| "boolean", |
| "equals", |
| new String[] {"Object"}, |
| new String[] {"obj"}, |
| null); |
| mJoust.writeStatement("if (this == obj) return true"); |
| mJoust.writeStatement("if (!(obj instanceof " + shortClassName + ")) return false"); |
| mJoust.writeStatement("final " + shortClassName + " x = (" + shortClassName + ") obj"); |
| if (enumHelper.isArray() && enumHelper.isBinary()) { |
| mJoust.writeStatement("if (x." + instanceVarName + ".length != " + instanceVarName + |
| ".length) return false"); |
| mJoust.writeStatement("boolean b = true"); |
| mJoust.writeStatement("for (int i = 0; i < " + instanceVarName + ".length && b; i++) " + |
| "b &= Arrays.equals(x." + instanceVarName + "[i], " + instanceVarName + "[i])"); |
| mJoust.writeStatement("return b"); |
| } |
| else if (enumHelper.isArray()) |
| mJoust.writeStatement("if (Arrays.equals(x." + instanceVarName + ", " + instanceVarName + ")) return true"); |
| else |
| mJoust.writeStatement("if (" + enumHelper.getEquals("x." + instanceVarName, instanceVarName) + ") return true"); |
| mJoust.writeReturnStatement(mJoust.getExpressionFactory().createBoolean(false)); |
| mJoust.endMethodOrConstructor(); |
| |
| // Implementation of the hashCode() method |
| mJoust.startMethod(Modifier.PUBLIC, |
| "int", |
| "hashCode", |
| null, null, null); |
| if (enumHelper.isArray()) { |
| mJoust.writeStatement("int val = 0;"); |
| mJoust.writeStatement("for (int i = 0; i < " + instanceVarName + ".length; i++) " + |
| "{ val *= 19; val += " + |
| enumHelper.getHashCode(instanceVarName + "[i]").getMemento().toString() + |
| "; }"); |
| mJoust.writeStatement("return val"); |
| } |
| else |
| mJoust.writeReturnStatement(enumHelper.getHashCode(instanceVarName)); |
| mJoust.endMethodOrConstructor(); |
| |
| // Static class code |
| mJoust.startStaticInitializer(); |
| for (int i = 0; i < fieldNames.length; i++) { |
| String fieldName = fieldNames[i]; |
| if (useArrays) |
| mJoust.writeStatement(instanceMapName + ".put(" + |
| fieldName + ", " + fieldName + ")"); |
| else |
| mJoust.writeStatement(instanceMapName + ".put(" + |
| enumHelper.getObjectVersion("_" + fieldName) + ", " + |
| fieldName + ")"); |
| } |
| mJoust.endMethodOrConstructor(); |
| mJoust.endClassOrInterface(); |
| } |
| |
| private String pickUniqueFieldName(String getter, Set seenNames) { |
| String baseName; |
| |
| if (getter.length() > 3 && getter.startsWith("get")) |
| baseName = Character.toLowerCase(getter.charAt(3)) + getter.substring(4); |
| else |
| baseName = "field"; |
| |
| String fieldName = baseName; |
| if (!NameUtil.isValidJavaIdentifier(fieldName)) |
| fieldName = "_" + fieldName; |
| for (int i = 1; seenNames.contains(fieldName); i += 1) |
| fieldName = baseName + i; |
| |
| seenNames.add(fieldName); |
| return fieldName; |
| } |
| |
| |
| // ======================================================================== |
| // main method - for quick debugging |
| |
| public static void main(String[] schemas) { |
| try { |
| File[] schemaFiles = new File[schemas.length]; |
| for (int i = 0; i < schemas.length; i++) schemaFiles[i] = new File(schemas[i]); |
| XmlObject[] xsds = new XmlObject[schemas.length]; |
| for (int i = 0; i < xsds.length; i++) { |
| xsds[i] = SchemaDocument.Factory.parse(new File(schemas[i])); |
| } |
| SchemaTypeLoader soapencLoader = org.apache.xmlbeans.impl.schema.SoapEncSchemaTypeSystem.get(); |
| SchemaTypeLoader xsdLoader = XmlBeans.getBuiltinTypeSystem(); |
| SchemaTypeSystem sts = |
| XmlBeans.compileXsd(xsds, |
| XmlBeans.typeLoaderUnion |
| (new SchemaTypeLoader[] {xsdLoader, soapencLoader}), |
| null); |
| Schema2Java s2j = new Schema2Java(sts); |
| s2j.setVerbose(true); |
| s2j.setJaxRpcRules(true); |
| TylarWriter tw = new DebugTylarWriter(); |
| s2j.bind(tw); |
| tw.close(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| System.err.flush(); |
| System.out.flush(); |
| } |
| } |