Skip to content

Commit

Permalink
Correctly tracking the scoped methods of ObjectFactory (fixes #72).
Browse files Browse the repository at this point in the history
  • Loading branch information
dmak committed Jan 23, 2023
1 parent 4c200e7 commit a33511f
Show file tree
Hide file tree
Showing 9 changed files with 297 additions and 25 deletions.
18 changes: 9 additions & 9 deletions src/main/java/com/sun/tools/xjc/addon/xew/Candidate.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -43,7 +42,8 @@ public final class Candidate {

private final boolean valueObjectDisabled;

private final Map<String, ScopedElementInfo> scopedElementInfos = new HashMap<>();
// Order matters as it affects the order of generated methods in Object Factory:
private final Map<JMethod, ScopedMethodInfo> scopedFactoryMethods = new LinkedHashMap<>();

/**
* By default the candidate is marked for removal unless something prevents it from being removed.
Expand All @@ -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) {
Expand All @@ -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:
Expand All @@ -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()));
}
Expand Down Expand Up @@ -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<String, ScopedElementInfo> getScopedElementInfos() {
return scopedElementInfos;
public Map<JMethod, ScopedMethodInfo> getScopedFactoryMethods() {
return scopedFactoryMethods;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
* }
* </pre>
*/
public final class ScopedElementInfo {
public final class ScopedMethodInfo {

/**
* Element name ("post-office").
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -492,7 +492,7 @@ else if (candidateFieldPropertyInfo instanceof CReferencePropertyInfo) {
* {@code TypeClass (is a collection type) -> ContainerClass (marked for removal) -> ElementClass}<br>
* we need to get<br>
* {@code TypeClass -> ElementClass}.<br>
* 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<String>":
Expand All @@ -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;
Expand All @@ -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<ScopedElementInfo> scopedElementInfos, JDefinedClass targetClass,
Collection<ScopedMethodInfo> 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
Expand Down Expand Up @@ -758,15 +758,17 @@ private int deleteCandidates(Outline outline, Collection<Candidate> 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());
}
Expand All @@ -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();
Expand Down
140 changes: 140 additions & 0 deletions src/test/generated_resources/inner_scoped_element/Catalogue.java
Original file line number Diff line number Diff line change
@@ -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;


/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;sequence&gt;
* &lt;element name="stockage_collection"&gt;
* &lt;complexType&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;sequence minOccurs="0"&gt;
* &lt;element name="stockage" maxOccurs="unbounded" minOccurs="0"&gt;
* &lt;complexType&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;all&gt;
* &lt;element name="collection" minOccurs="0"&gt;
* &lt;complexType&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;sequence maxOccurs="unbounded" minOccurs="0"&gt;
* &lt;element name="effect" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;element name="term" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;/sequence&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* &lt;/element&gt;
* &lt;/all&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* &lt;/element&gt;
* &lt;/sequence&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* &lt;/element&gt;
* &lt;/sequence&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"stockageCollection"
})
@XmlRootElement(name = "catalogue")
public class Catalogue {

@XmlElementWrapper(name = "stockage_collection", required = true)
@XmlElement(name = "stockage")
protected List<Catalogue.Stockage> stockageCollection = new ArrayList<Catalogue.Stockage>();

public List<Catalogue.Stockage> getStockageCollection() {
return stockageCollection;
}

public void setStockageCollection(List<Catalogue.Stockage> stockageCollection) {
this.stockageCollection = stockageCollection;
}


/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;all&gt;
* &lt;element name="collection" minOccurs="0"&gt;
* &lt;complexType&gt;
* &lt;complexContent&gt;
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType"&gt;
* &lt;sequence maxOccurs="unbounded" minOccurs="0"&gt;
* &lt;element name="effect" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;element name="term" type="{http://www.w3.org/2001/XMLSchema}string" minOccurs="0"/&gt;
* &lt;/sequence&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* &lt;/element&gt;
* &lt;/all&gt;
* &lt;/restriction&gt;
* &lt;/complexContent&gt;
* &lt;/complexType&gt;
* </pre>
*
*
*/
@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<JAXBElement<String>> collection = new ArrayList<JAXBElement<String>>();

public List<JAXBElement<String>> getCollection() {
return collection;
}

public void setCollection(List<JAXBElement<String>> collection) {
this.collection = collection;
}

}

}
Original file line number Diff line number Diff line change
@@ -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.
* <p>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<String> createCatalogueStockageEffect(String value) {
return new JAXBElement<String>(new QName("", "effect"), String.class, Catalogue.Stockage.class, value);
}

@XmlElementDecl(namespace = "", name = "term", scope = Catalogue.Stockage.class)
public JAXBElement<String> createCatalogueStockageTerm(String value) {
return new JAXBElement<String>(new QName("", "term"), String.class, Catalogue.Stockage.class, value);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,13 @@ public void testInnerElement() throws Exception {
runTest("inner-element", extraXewOptions, true, classesToCheck);
}

@Test
public void testInnerScopedElement() throws Exception {
List<String> extraXewOptions = asList("-verbose", "-Xxew:instantiate early");
List<String> classesToCheck = asList("Catalogue");
runTest("inner-scoped-element", extraXewOptions, false, classesToCheck);
}

@Test
public void testInnerElementWithValueObjects() throws Exception {
List<String> classesToCheck = asList("Article", "Articles", "ArticlesCollections", "Filesystem", "Publisher",
Expand Down
Loading

0 comments on commit a33511f

Please sign in to comment.