diff --git a/src/main/java/com/sun/tools/xjc/addon/xew/Candidate.java b/src/main/java/com/sun/tools/xjc/addon/xew/Candidate.java index 0dabbfc..a34c95d 100644 --- a/src/main/java/com/sun/tools/xjc/addon/xew/Candidate.java +++ b/src/main/java/com/sun/tools/xjc/addon/xew/Candidate.java @@ -7,7 +7,6 @@ import static com.sun.tools.xjc.addon.xew.XmlElementWrapperPlugin.FACTORY_CLASS_NAME; import java.util.Collection; -import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; @@ -43,7 +42,8 @@ public final class Candidate { private final boolean valueObjectDisabled; - private final Map scopedElementInfos = new HashMap<>(); + // Order matters as it affects the order of generated methods in Object Factory: + private final Map scopedFactoryMethods = new LinkedHashMap<>(); /** * By default the candidate is marked for removal unless something prevents it from being removed. @@ -65,7 +65,7 @@ public final class Candidate { this.fieldParametrisationImpl = fieldParametrisationImpl; this.valueObjectDisabled = addObjectFactoryForClass(candidateClass); this.fieldTargetNamespace = getTargetNamespace(candidateClassInfo, xmlSchemaModelClass); - collectScopedElementInfos(xmlElementDeclModelClass); + collectScopedFactoryMethods(xmlElementDeclModelClass); } private String getTargetNamespace(CClassInfo candidateClassInfo, JClass xmlSchemaModelClass) { @@ -90,7 +90,7 @@ private String getTargetNamespace(CClassInfo candidateClassInfo, JClass xmlSchem return null; } - private void collectScopedElementInfos(JClass xmlElementDeclModelClass) { + private void collectScopedFactoryMethods(JClass xmlElementDeclModelClass) { String dotClazz = candidateClass.fullName() + ".class"; // Only value Object Factory methods are inspected: @@ -102,8 +102,8 @@ private void collectScopedElementInfos(JClass xmlElementDeclModelClass) { continue; } - scopedElementInfos.put(method.name(), - new ScopedElementInfo(getAnnotationMemberValue(xmlElementDeclAnnotation, "name"), + scopedFactoryMethods.put(method, + new ScopedMethodInfo(getAnnotationMemberValue(xmlElementDeclAnnotation, "name"), getAnnotationMemberValue(xmlElementDeclAnnotation, "namespace"), method.params().get(0).type())); } @@ -176,12 +176,12 @@ public JDefinedClass getFieldParametrisationImpl() { } /** - * Return information about scoped elements, that have this candidate as a scope. + * Return information about scoped methods that have this candidate as a scope. * * @return object factory method name -to- element info map */ - public Map getScopedElementInfos() { - return scopedElementInfos; + public Map getScopedFactoryMethods() { + return scopedFactoryMethods; } /** diff --git a/src/main/java/com/sun/tools/xjc/addon/xew/ScopedElementInfo.java b/src/main/java/com/sun/tools/xjc/addon/xew/ScopedMethodInfo.java similarity index 91% rename from src/main/java/com/sun/tools/xjc/addon/xew/ScopedElementInfo.java rename to src/main/java/com/sun/tools/xjc/addon/xew/ScopedMethodInfo.java index d9707fb..c8e385c 100644 --- a/src/main/java/com/sun/tools/xjc/addon/xew/ScopedElementInfo.java +++ b/src/main/java/com/sun/tools/xjc/addon/xew/ScopedMethodInfo.java @@ -23,7 +23,7 @@ * } * */ -public final class ScopedElementInfo { +public final class ScopedMethodInfo { /** * Element name ("post-office"). @@ -40,7 +40,7 @@ public final class ScopedElementInfo { */ public final JType type; - public ScopedElementInfo(String name, String namespace, JType type) { + public ScopedMethodInfo(String name, String namespace, JType type) { this.name = name; this.namespace = namespace; this.type = type; diff --git a/src/main/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPlugin.java b/src/main/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPlugin.java index 46540ff..57ef24c 100644 --- a/src/main/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPlugin.java +++ b/src/main/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPlugin.java @@ -463,7 +463,7 @@ else if (candidateFieldPropertyInfo instanceof CReferencePropertyInfo) { // Adapt factory class: for (JDefinedClass objectFactoryClass : candidate.getObjectFactoryClasses()) { modificationCount += createScopedFactoryMethods(codeModel, objectFactoryClass, - candidate.getScopedElementInfos().values(), targetClass, xmlElementDeclModelClass, + candidate.getScopedFactoryMethods().values(), targetClass, xmlElementDeclModelClass, jaxbElementModelClass, qNameModelClass); } @@ -492,7 +492,7 @@ else if (candidateFieldPropertyInfo instanceof CReferencePropertyInfo) { * {@code TypeClass (is a collection type) -> ContainerClass (marked for removal) -> ElementClass}
* we need to get
* {@code TypeClass -> ElementClass}.
- * Also this move should be reflected on factory method names. + * Also this move should be reflected on factory method names (and scope methods of other candidates as well). */ private boolean moveInnerClassToParent(Outline outline, Candidate candidate) { // Skip basic parametrisations like "List": @@ -509,18 +509,18 @@ private boolean moveInnerClassToParent(Outline outline, Candidate candidate) { JDefinedClass fieldParametrisationClass = candidate.getFieldParametrisationClass(); - String oldFactoryMethodName = fieldParametrisationClass.outer().name() + fieldParametrisationClass.name(); + String oldMethodName = fieldParametrisationClass.outer().name() + fieldParametrisationClass.name(); moveClassLevelUp(outline, fieldParametrisationImpl); - renameFactoryMethod(fieldParametrisationImpl._package()._getClass(FACTORY_CLASS_NAME), oldFactoryMethodName, + renameFactoryMethod(fieldParametrisationImpl._package()._getClass(FACTORY_CLASS_NAME), oldMethodName, fieldParametrisationClass.name()); if (candidate.isValueObjectDisabled()) { moveClassLevelUp(outline, fieldParametrisationClass); - renameFactoryMethod(fieldParametrisationClass._package()._getClass(FACTORY_CLASS_NAME), - oldFactoryMethodName, fieldParametrisationClass.name()); + renameFactoryMethod(fieldParametrisationClass._package()._getClass(FACTORY_CLASS_NAME), oldMethodName, + fieldParametrisationClass.name()); } return true; @@ -539,11 +539,11 @@ private boolean moveInnerClassToParent(Outline outline, Candidate candidate) { * @see com.sun.tools.xjc.generator.bean.ObjectFactoryGenerator */ private int createScopedFactoryMethods(JCodeModel codeModel, JDefinedClass factoryClass, - Collection scopedElementInfos, JDefinedClass targetClass, + Collection scopedFactoryMethodInfos, JDefinedClass targetClass, JClass xmlElementDeclModelClass, JClass jaxbElementModelClass, JClass qNameModelClass) { int createdMethods = 0; - NEXT: for (ScopedElementInfo info : scopedElementInfos) { + NEXT: for (ScopedMethodInfo info : scopedFactoryMethodInfos) { String dotClazz = targetClass.fullName() + ".class"; // First check that such factory method has not yet been created. It can be the case if target class @@ -758,15 +758,17 @@ private int deleteCandidates(Outline outline, Collection candidates) /** * Rename methods in factory class: {@code createABC() -> createAC()}. */ - private void renameFactoryMethod(JDefinedClass factoryClass, String oldMethodName, String newMethodName) { + private void renameFactoryMethod(JDefinedClass factoryClass, String oldMethodNameSuffix, String newMethodNameSuffix) { for (JMethod method : factoryClass.methods()) { String methodName = method.name(); - if (!methodName.contains(oldMethodName)) { + if (!methodName.contains(oldMethodNameSuffix)) { continue; } - method.name(methodName.replace(oldMethodName, newMethodName)); + method.name(methodName.replace(oldMethodNameSuffix, newMethodNameSuffix)); + + // Method renaming for scoped methods is automatically applied. writeSummary("\tRenamed " + methodName + " -> " + method.name() + " in " + factoryClass.fullName()); } @@ -791,7 +793,7 @@ private int deleteFactoryMethod(JDefinedClass factoryClass, Candidate candidate) if ((method.type() instanceof JDefinedClass && ((JDefinedClass) method.type()).isAssignableFrom(candidate.getClazz())) || isListedAsParametrisation(candidate.getClazz(), method.type()) - || candidate.getScopedElementInfos().containsKey(method.name())) { + || candidate.getScopedFactoryMethods().containsKey(method)) { writeSummary("\tRemoving factory method [" + method.type().fullName() + "#" + method.name() + "()] from " + factoryClass.fullName()); iter.remove(); diff --git a/src/test/generated_resources/inner_scoped_element/Catalogue.java b/src/test/generated_resources/inner_scoped_element/Catalogue.java new file mode 100644 index 0000000..da83bf3 --- /dev/null +++ b/src/test/generated_resources/inner_scoped_element/Catalogue.java @@ -0,0 +1,140 @@ + +package inner_scoped_element; + +import java.util.ArrayList; +import java.util.List; +import jakarta.xml.bind.JAXBElement; +import jakarta.xml.bind.annotation.XmlAccessType; +import jakarta.xml.bind.annotation.XmlAccessorType; +import jakarta.xml.bind.annotation.XmlElement; +import jakarta.xml.bind.annotation.XmlElementRef; +import jakarta.xml.bind.annotation.XmlElementRefs; +import jakarta.xml.bind.annotation.XmlElementWrapper; +import jakarta.xml.bind.annotation.XmlRootElement; +import jakarta.xml.bind.annotation.XmlType; + + +/** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+ * <complexType>
+ *   <complexContent>
+ *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       <sequence>
+ *         <element name="stockage_collection">
+ *           <complexType>
+ *             <complexContent>
+ *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                 <sequence minOccurs="0">
+ *                   <element name="stockage" maxOccurs="unbounded" minOccurs="0">
+ *                     <complexType>
+ *                       <complexContent>
+ *                         <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                           <all>
+ *                             <element name="collection" minOccurs="0">
+ *                               <complexType>
+ *                                 <complexContent>
+ *                                   <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *                                     <sequence maxOccurs="unbounded" minOccurs="0">
+ *                                       <element name="effect" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                                       <element name="term" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+ *                                     </sequence>
+ *                                   </restriction>
+ *                                 </complexContent>
+ *                               </complexType>
+ *                             </element>
+ *                           </all>
+ *                         </restriction>
+ *                       </complexContent>
+ *                     </complexType>
+ *                   </element>
+ *                 </sequence>
+ *               </restriction>
+ *             </complexContent>
+ *           </complexType>
+ *         </element>
+ *       </sequence>
+ *     </restriction>
+ *   </complexContent>
+ * </complexType>
+ * 
+ * + * + */ +@XmlAccessorType(XmlAccessType.FIELD) +@XmlType(name = "", propOrder = { + "stockageCollection" +}) +@XmlRootElement(name = "catalogue") +public class Catalogue { + + @XmlElementWrapper(name = "stockage_collection", required = true) + @XmlElement(name = "stockage") + protected List stockageCollection = new ArrayList(); + + public List getStockageCollection() { + return stockageCollection; + } + + public void setStockageCollection(List stockageCollection) { + this.stockageCollection = stockageCollection; + } + + + /** + *

Java class for anonymous complex type. + * + *

The following schema fragment specifies the expected content contained within this class. + * + *

+     * <complexType>
+     *   <complexContent>
+     *     <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *       <all>
+     *         <element name="collection" minOccurs="0">
+     *           <complexType>
+     *             <complexContent>
+     *               <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+     *                 <sequence maxOccurs="unbounded" minOccurs="0">
+     *                   <element name="effect" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                   <element name="term" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/>
+     *                 </sequence>
+     *               </restriction>
+     *             </complexContent>
+     *           </complexType>
+     *         </element>
+     *       </all>
+     *     </restriction>
+     *   </complexContent>
+     * </complexType>
+     * 
+ * + * + */ + @XmlAccessorType(XmlAccessType.FIELD) + @XmlType(name = "", propOrder = { + + }) + public static class Stockage { + + @XmlElementWrapper + @XmlElementRefs({ + @XmlElementRef(name = "effect", type = JAXBElement.class, required = false), + @XmlElementRef(name = "term", type = JAXBElement.class, required = false) + }) + protected List> collection = new ArrayList>(); + + public List> getCollection() { + return collection; + } + + public void setCollection(List> collection) { + this.collection = collection; + } + + } + +} diff --git a/src/test/generated_resources/inner_scoped_element/ObjectFactory.java b/src/test/generated_resources/inner_scoped_element/ObjectFactory.java new file mode 100644 index 0000000..685a398 --- /dev/null +++ b/src/test/generated_resources/inner_scoped_element/ObjectFactory.java @@ -0,0 +1,63 @@ + +package inner_scoped_element; + +import javax.xml.namespace.QName; +import jakarta.xml.bind.JAXBElement; +import jakarta.xml.bind.annotation.XmlElementDecl; +import jakarta.xml.bind.annotation.XmlRegistry; + + +/** + * This object contains factory methods for each + * Java content interface and Java element interface + * generated in the inner_scoped_element package. + *

An ObjectFactory allows you to programatically + * construct new instances of the Java representation + * for XML content. The Java representation of XML + * content can consist of schema derived interfaces + * and classes representing the binding of schema + * type definitions, element declarations and model + * groups. Factory methods for each of these are + * provided in this class. + * + */ +@XmlRegistry +public class ObjectFactory { + + private final static QName _CatalogueStockageCollectionStockageCollectionEffect_QNAME = new QName("", "effect"); + private final static QName _CatalogueStockageCollectionStockageCollectionTerm_QNAME = new QName("", "term"); + + /** + * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: inner_scoped_element + * + */ + public ObjectFactory() { + } + + /** + * Create an instance of {@link Catalogue } + * + */ + public Catalogue createCatalogue() { + return new Catalogue(); + } + + /** + * Create an instance of {@link Catalogue.Stockage } + * + */ + public Catalogue.Stockage createCatalogueStockage() { + return new Catalogue.Stockage(); + } + + @XmlElementDecl(namespace = "", name = "effect", scope = Catalogue.Stockage.class) + public JAXBElement createCatalogueStockageEffect(String value) { + return new JAXBElement(new QName("", "effect"), String.class, Catalogue.Stockage.class, value); + } + + @XmlElementDecl(namespace = "", name = "term", scope = Catalogue.Stockage.class) + public JAXBElement createCatalogueStockageTerm(String value) { + return new JAXBElement(new QName("", "term"), String.class, Catalogue.Stockage.class, value); + } + +} diff --git a/src/test/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPluginTest.java b/src/test/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPluginTest.java index bf8b86d..40ad136 100644 --- a/src/test/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPluginTest.java +++ b/src/test/java/com/sun/tools/xjc/addon/xew/XmlElementWrapperPluginTest.java @@ -144,6 +144,13 @@ public void testInnerElement() throws Exception { runTest("inner-element", extraXewOptions, true, classesToCheck); } + @Test + public void testInnerScopedElement() throws Exception { + List extraXewOptions = asList("-verbose", "-Xxew:instantiate early"); + List classesToCheck = asList("Catalogue"); + runTest("inner-scoped-element", extraXewOptions, false, classesToCheck); + } + @Test public void testInnerElementWithValueObjects() throws Exception { List classesToCheck = asList("Article", "Articles", "ArticlesCollections", "Filesystem", "Publisher", diff --git a/src/test/resources/com/sun/tools/xjc/addon/xew/inner-scoped-element.xml b/src/test/resources/com/sun/tools/xjc/addon/xew/inner-scoped-element.xml new file mode 100644 index 0000000..9d8d955 --- /dev/null +++ b/src/test/resources/com/sun/tools/xjc/addon/xew/inner-scoped-element.xml @@ -0,0 +1,19 @@ + + + + + + solar panels + system performance + energy efficiency + microinverter + + + + + shaded panel + maintenance costs + + + + diff --git a/src/test/resources/com/sun/tools/xjc/addon/xew/inner-scoped-element.xsd b/src/test/resources/com/sun/tools/xjc/addon/xew/inner-scoped-element.xsd new file mode 100644 index 0000000..7f2fac9 --- /dev/null +++ b/src/test/resources/com/sun/tools/xjc/addon/xew/inner-scoped-element.xsd @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/com/sun/tools/xjc/addon/xew/publisher-shared.xsd b/src/test/resources/com/sun/tools/xjc/addon/xew/publisher-shared.xsd index 1902cea..1cdce5f 100644 --- a/src/test/resources/com/sun/tools/xjc/addon/xew/publisher-shared.xsd +++ b/src/test/resources/com/sun/tools/xjc/addon/xew/publisher-shared.xsd @@ -1,7 +1,7 @@ @@ -30,7 +30,6 @@ -