All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.tools.xjc.addon.xew.Candidate Maven / Gradle / Ivy

Go to download

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() + "]";
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy