if (!(field.getRawType() instanceof JClass)) {
continue;
}
JClass fieldType = (JClass) field.getRawType();
CPropertyInfo fieldPropertyInfo = field.getPropertyInfo();
// For example, XSD attributes (PropertyKind.ATTRIBUTE) are always simple types:
if (!(fieldPropertyInfo.kind() == PropertyKind.ELEMENT || fieldPropertyInfo.kind() == PropertyKind.REFERENCE)) {
continue;
}
String fieldName = fieldPropertyInfo.getName(false);
Candidate candidate = null;
for (Candidate c : candidatesMap.values()) {
// Skip fields with basic types as for example any class can be casted to Object.
if (fieldType.isAssignableFrom(c.getCandidateClass()) && !isHiddenClass(fieldType)) {
// If the given field has type T, it cannot be also in the list of parametrisations (e.g. T<T>).
candidate = c;
break;
}
// If the candidate T is referred from list of parametrisations (e.g. List<T>), it cannot be removed.
// However field substitutions will take place.
else if (isListedAsParametrisation(c.getCandidateClass(), fieldType)) {
logger.debug("Candidate " + c.getClassName() + " is listed as parametrisation of "
+ targetClass.fullName() + "#" + fieldName + " and hence won't be removed.");
c.unmarkForRemoval();
}
}
JFieldVar originalImplField = targetClass.fields().get(fieldName);
if (candidate == null) {
checkAnnotationReference(candidatesMap, originalImplField);
continue;
}
// We have a candidate field to be replaced with a wrapped version. Report finding to summary file.
writeSummary("\tReplacing field [" + fieldType.name() + " " + targetClass.fullName() + "#" + fieldName
+ "]");
candidate.incrementSubstitutions();
modificationCount++;
// The container class has to be deleted. Check that inner class has to be moved to it's parent.
if (moveInnerClassToParent(outline, candidate)) {
modificationCount++;
}
Configuration fieldConfiguration = applyConfigurationFromCustomizations(classConfiguration,
CustomizationUtils.getCustomizations(field));
List<JClass> fieldTypeParametrisations = candidate.getFieldClass().getTypeParameters();
// Create the new interface and collection classes using the specified interface and
// collection classes (configuration) with an element type corresponding to
// the element type from the collection present in the candidate class (narrowing).
JClass collectionInterfaceClass = codeModel.ref(fieldConfiguration.getCollectionInterfaceClass())
.narrow(fieldTypeParametrisations);
JClass collectionImplClass = codeModel.ref(fieldConfiguration.getCollectionImplClass()).narrow(
fieldTypeParametrisations);
boolean pluralFormWasApplied = false;
// Apply the plural form if there are no customizations. Assuming that customization is correct as may define the
// plural form in more correct way, e.g. "field[s]OfScience" instead of "fieldOfScience[s]".
if (fieldConfiguration.isApplyPluralForm() && !hasPropertyNameCustomization(fieldPropertyInfo)) {
String oldFieldName = fieldName;
// Taken from com.sun.tools.xjc.reader.xmlschema.ParticleBinder#makeJavaName():
fieldName = JJavaName.getPluralForm(fieldName);
// The field e.g. "return" was escaped as "_return", but after conversion to plural
// it became valid Java identifier, so we remove the leading "_":
if (fieldName.startsWith("_") && JJavaName.isJavaIdentifier(fieldName.substring(1))) {
fieldName = fieldName.substring(1);
}
if (!fieldName.equals(oldFieldName)) {
pluralFormWasApplied = true;
originalImplField.name(fieldName);
fieldPropertyInfo.setName(false, fieldName);
// Correct the @XmlType class-level annotation:
JAnnotationArrayMember propOrderValue = (JAnnotationArrayMember) getAnnotation(targetClass,
xmlTypeModelClass).getAnnotationMembers().get("propOrder");
if (propOrderValue != null) {
for (JAnnotationValue annotationValue : propOrderValue.annotations()) {
if (oldFieldName.equals(generableToString(annotationValue))) {
setPrivateField(annotationValue, "value", JExpr.lit(fieldName));
break;
}
}
}
}
}
// Transform the field accordingly.
originalImplField.type(collectionInterfaceClass);
// If instantiation is specified to be "early", add code for creating new instance of the collection class.
if (fieldConfiguration.getInstantiationMode() == Configuration.InstantiationMode.EARLY) {
logger.debug("Applying EARLY instantiation...");
// GENERATED CODE: ... fieldName = new C<T>();
originalImplField.init(JExpr._new(collectionImplClass));
}
// Annotate the field with the @XmlElementWrapper annotation using the original field name.
JAnnotationUse xmlElementWrapperAnnotation = originalImplField.annotate(xmlElementWrapperModelClass);
JAnnotationUse xmlElementOriginalAnnotation = getAnnotation(originalImplField, xmlElementModelClass);
// xmlElementOriginalAnnotation can be null:
JExpression wrapperXmlName = getAnnotationMemberExpression(xmlElementOriginalAnnotation, "name");
if (wrapperXmlName != null) {
xmlElementWrapperAnnotation.param("name", wrapperXmlName);
}
else if (fieldConfiguration.isApplyPluralForm()) {
xmlElementWrapperAnnotation.param("name", getXsdDeclaration(fieldPropertyInfo).getName());
}
JExpression wrapperXmlRequired = getAnnotationMemberExpression(xmlElementOriginalAnnotation, "required");
if (wrapperXmlRequired != null) {
xmlElementWrapperAnnotation.param("required", wrapperXmlRequired);
}
JExpression wrapperXmlNillable = getAnnotationMemberExpression(xmlElementOriginalAnnotation, "nillable");
if (wrapperXmlNillable != null) {
xmlElementWrapperAnnotation.param("nillable", wrapperXmlNillable);
}
// Namespace of the wrapper element
JExpression wrapperXmlNamespace = getAnnotationMemberExpression(xmlElementOriginalAnnotation,
"namespace");
if (wrapperXmlNamespace != null) {
xmlElementWrapperAnnotation.param("namespace", wrapperXmlNamespace);
}
if (xmlElementOriginalAnnotation != null) {
removeAnnotation(originalImplField, xmlElementOriginalAnnotation);
}
boolean xmlElementInfoWasTransferred = false;
// Transfer @XmlAnyElement, @XmlElementRefs, @XmlElements:
for (JClass annotationModelClass : new JClass[] { xmlAnyElementModelClass, xmlMixedModelClass,
xmlElementRefModelClass, xmlElementRefsModelClass, xmlElementsModelClass }) {
JAnnotationUse annotation = getAnnotation(candidate.getField(), annotationModelClass);
if (annotation != null) {
if (candidate.getFieldTargetNamespace() != null) {
JAnnotationArrayMember annotationArrayMember = (JAnnotationArrayMember) getAnnotationMember(
annotation, "value");
if (annotationArrayMember != null) {
for (JAnnotationUse subAnnotation : annotationArrayMember.annotations()) {
if (getAnnotationMemberExpression(subAnnotation, "namespace") == null) {
subAnnotation.param("namespace", candidate.getFieldTargetNamespace());
}
}
}
}
xmlElementInfoWasTransferred = true;
addAnnotation(originalImplField, annotation);
}
}
if (!xmlElementInfoWasTransferred) {
// Annotate the field with the @XmlElement annotation using the field name from the wrapped type as name.
// We cannot just re-use the same annotation object instance, as for example, we need to set XML name and this
// will impact the candidate field annotation in case candidate is unmarked from removal.
JAnnotationUse xmlElementAnnotation = originalImplField.annotate(xmlElementModelClass);
xmlElementOriginalAnnotation = getAnnotation(candidate.getField(), xmlElementModelClass);
// xmlElementOriginalAnnotation can be null:
JExpression xmlName = getAnnotationMemberExpression(xmlElementOriginalAnnotation, "name");
if (xmlName != null) {
xmlElementAnnotation.param("name", xmlName);
}
else {
xmlElementAnnotation.param("name", candidate.getFieldName());
}
JExpression xmlNamespace = getAnnotationMemberExpression(xmlElementOriginalAnnotation, "namespace");
if (xmlNamespace != null) {
xmlElementAnnotation.param("namespace", xmlNamespace);
}
else if (candidate.getFieldTargetNamespace() != null) {
xmlElementAnnotation.param("namespace", candidate.getFieldTargetNamespace());
}
JExpression type = getAnnotationMemberExpression(xmlElementOriginalAnnotation, "type");
if (type != null) {
xmlElementAnnotation.param("type", type);
}
}
JAnnotationUse adapterAnnotation = getAnnotation(candidate.getField(), xmlJavaTypeAdapterModelClass);
if (adapterAnnotation != null) {
addAnnotation(originalImplField, adapterAnnotation);
}
// Same as fieldName, but used as getter/setter method name:
String propertyName = fieldPropertyInfo.getName(true);
JDefinedClass implementationInterface = null;
for (Iterator<JClass> iter = targetClass._implements(); iter.hasNext();) {
JClass interfaceClass = iter.next();
// If value class implements some JVM interface it is not considered as such interface cannot be modified:
if (interfaceClass instanceof JDefinedClass
&& deleteSettersGetters((JDefinedClass) interfaceClass, propertyName)) {
implementationInterface = (JDefinedClass) interfaceClass;
break;
}
}
// Find original getter and setter methods to remove.
deleteSettersGetters(targetClass, propertyName);
if (pluralFormWasApplied) {
propertyName = JJavaName.getPluralForm(propertyName);
fieldPropertyInfo.setName(true, propertyName);
}
// Add a new getter method returning the (wrapped) field added.
// GENERATED CODE: public I<T> getFieldName() { ... return fieldName; }
JMethod getterMethod = targetClass.method(JMod.PUBLIC, collectionInterfaceClass, "get" + propertyName);