com.sun.tools.xjc.addon.xew.Candidate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jaxb-xew-plugin Show documentation
Show all versions of jaxb-xew-plugin Show documentation
This JAXB plugin utilizes the power of @XmlElementWrapper annotation. Originally xjc trends to create wrapper classes which are the containers for collections. This plugin goes through all properties to find ones which can be represented in the model in more optimal way.
The newest version!
package com.sun.tools.xjc.addon.xew;
import static com.sun.tools.xjc.addon.xew.CommonUtils.getAnnotation;
import static com.sun.tools.xjc.addon.xew.CommonUtils.getAnnotationMemberValue;
import static com.sun.tools.xjc.addon.xew.CommonUtils.getXsdDeclaration;
import static com.sun.tools.xjc.addon.xew.CommonUtils.isHiddenClass;
import static com.sun.tools.xjc.addon.xew.XmlElementWrapperPlugin.FACTORY_CLASS_NAME;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import com.sun.codemodel.JAnnotationUse;
import com.sun.codemodel.JClass;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JFieldVar;
import com.sun.codemodel.JMethod;
import com.sun.tools.xjc.model.CClassInfo;
import com.sun.tools.xjc.model.CPropertyInfo;
import com.sun.xml.xsom.XSDeclaration;
/**
* Describes the collection container class - a candidate for removal. This class class has only one field - collection
* of objects.
*/
public final class Candidate {
private final JDefinedClass candidateClass;
private final JFieldVar field;
private final CPropertyInfo fieldPropertyInfo;
private final String fieldTargetNamespace;
private final Collection parametrisationInfos;
// Order matters (value Object Factory is first):
private final Map objectFactoryClasses = new LinkedHashMap<>();
private final boolean valueObjectDisabled;
// 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.
*/
private boolean markedForRemoval = true;
/**
* Number of times this candidate has been substituted in the model.
*/
private int substitutionsCount;
Candidate(JDefinedClass candidateClass, CClassInfo candidateClassInfo, JFieldVar field,
Collection parametrisationInfos, JClass xmlElementDeclModelClass,
JClass xmlSchemaModelClass) {
this.candidateClass = candidateClass;
this.field = field;
this.fieldPropertyInfo = candidateClassInfo.getProperty(field.name());
this.parametrisationInfos = parametrisationInfos;
this.valueObjectDisabled = addObjectFactoryForClass(candidateClass);
this.fieldTargetNamespace = getTargetNamespace(candidateClassInfo, xmlSchemaModelClass);
collectScopedFactoryMethods(xmlElementDeclModelClass);
}
private String getTargetNamespace(CClassInfo candidateClassInfo, JClass xmlSchemaModelClass) {
XSDeclaration xsdDeclaration = getXsdDeclaration(candidateClassInfo.getProperty(field.name()));
if (xsdDeclaration != null && !xsdDeclaration.getTargetNamespace().isEmpty()) {
return xsdDeclaration.getTargetNamespace();
}
else {
// Default (mostly used) namespace is generated as annotation for the package,
// see com.sun.tools.xjc.generator.bean.PackageOutlineImpl#calcDefaultValues()
for (JDefinedClass objectFactoryClass : objectFactoryClasses.values()) {
JAnnotationUse schemaAnnotation = getAnnotation(objectFactoryClass.getPackage(), xmlSchemaModelClass);
String elementFormDefault = getAnnotationMemberValue(schemaAnnotation, "elementFormDefault");
if (elementFormDefault != null && elementFormDefault.endsWith(".QUALIFIED")) {
return getAnnotationMemberValue(schemaAnnotation, "namespace");
}
}
}
return null;
}
private void collectScopedFactoryMethods(JClass xmlElementDeclModelClass) {
String dotClazz = candidateClass.fullName() + ".class";
// Only value Object Factory methods are inspected:
for (JMethod method : objectFactoryClasses.values().iterator().next().methods()) {
JAnnotationUse xmlElementDeclAnnotation = getAnnotation(method, xmlElementDeclModelClass);
String scope = getAnnotationMemberValue(xmlElementDeclAnnotation, "scope");
if (scope == null || !dotClazz.equals(scope)) {
continue;
}
scopedFactoryMethods.put(method,
new ScopedMethodInfo(getAnnotationMemberValue(xmlElementDeclAnnotation, "name"),
getAnnotationMemberValue(xmlElementDeclAnnotation, "namespace"),
method.params().get(0).type()));
}
}
/**
* Container class
*/
public JDefinedClass getClazz() {
return candidateClass;
}
/**
* Container class name
*/
public String getClassName() {
return candidateClass.fullName();
}
/**
* The only field in container class (collection property).
*/
public JFieldVar getField() {
return field;
}
/**
* The name of the only field in container class.
*/
public String getFieldName() {
return field.name();
}
/**
* The class of the only field in container class (collection interface or particular implementation).
*/
public JClass getFieldClass() {
return (JClass) field.type();
}
/**
* The corresponding property info of the only field in container class.
*/
public CPropertyInfo getFieldPropertyInfo() {
return fieldPropertyInfo;
}
/**
* The XSD namespace of the property associated with a field.
*/
public String getFieldTargetNamespace() {
return fieldTargetNamespace;
}
/**
* The list of parametrisation classes of the field (collection types). In case of basic parametrisation like
* {@code List} this collection is empty.
*/
public Collection getParametrisationInfos() {
return parametrisationInfos;
}
/**
* Return information about scoped methods that have this candidate as a scope.
*
* @return object factory method name -to- element info map
*/
public Map getScopedFactoryMethods() {
return scopedFactoryMethods;
}
/**
* Object Factory classes for value (implementation) classes, interface classes and extra packages. Cannot be empty.
*/
public Collection getObjectFactoryClasses() {
return objectFactoryClasses.values();
}
/**
* For the given class locate and add Object Factory classes to the map.
*
* @return {@code true} if value class generation is enabled
*/
public boolean addObjectFactoryForClass(JDefinedClass clazz) {
JDefinedClass valueObjectFactoryClass = clazz._package()._getClass(FACTORY_CLASS_NAME);
if (objectFactoryClasses.containsKey(valueObjectFactoryClass.fullName())) {
return false;
}
objectFactoryClasses.put(valueObjectFactoryClass.fullName(), valueObjectFactoryClass);
JDefinedClass objectFactoryClass = null;
// If class has a non-hidden interface, then there is object factory in another package.
for (Iterator iter = clazz._implements(); iter.hasNext();) {
JClass interfaceClass = iter.next();
if (!isHiddenClass(interfaceClass)) {
objectFactoryClass = interfaceClass._package()._getClass(FACTORY_CLASS_NAME);
if (objectFactoryClass != null) {
objectFactoryClasses.put(objectFactoryClass.fullName(), objectFactoryClass);
}
}
}
return objectFactoryClass != null;
}
/**
* Returns {@code true} if the setting {@code } is active.
*/
public boolean isValueObjectDisabled() {
return valueObjectDisabled;
}
/**
* Has given candidate green light to be removed?
*/
public boolean canBeRemoved() {
return markedForRemoval && substitutionsCount > 0;
}
/**
* Increments number of substitutions for this candidate.
*/
public void incrementSubstitutions() {
substitutionsCount++;
}
/**
* Signal that this candidate should not be removed from model on some reason.
*/
public void unmarkForRemoval() {
this.markedForRemoval = false;
}
@Override
public String toString() {
return "Candidate[" + getClassName() + " in field " + getFieldClass().name() + " " + getFieldName() + "]";
}
}