blob: cb52583cecb79d827bd701abcbf37cb7bbf9d461 [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// dmccann - June 17/2009 - 2.0 - Initial implementation
// Martin Vojtek - July 8/2014 - 2.6 - XmlNullPolicy and XmlElementNillable
package org.eclipse.persistence.jaxb.compiler;
import static org.eclipse.persistence.jaxb.javamodel.Helper.getQualifiedJavaTypeName;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import jakarta.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import org.eclipse.persistence.exceptions.JAXBException;
import org.eclipse.persistence.internal.oxm.Constants;
import org.eclipse.persistence.internal.oxm.XMLConversionManager;
import org.eclipse.persistence.jaxb.TypeMappingInfo;
import org.eclipse.persistence.jaxb.javamodel.Helper;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.javamodel.JavaField;
import org.eclipse.persistence.jaxb.javamodel.JavaHasAnnotations;
import org.eclipse.persistence.jaxb.javamodel.JavaMethod;
import org.eclipse.persistence.jaxb.javamodel.JavaModelInput;
import org.eclipse.persistence.jaxb.javamodel.reflection.JavaClassImpl;
import org.eclipse.persistence.jaxb.xmlmodel.JavaAttribute;
import org.eclipse.persistence.jaxb.xmlmodel.JavaType;
import org.eclipse.persistence.jaxb.xmlmodel.JavaType.JavaAttributes;
import org.eclipse.persistence.jaxb.xmlmodel.XmlAbstractNullPolicy;
import org.eclipse.persistence.jaxb.xmlmodel.XmlAccessType;
import org.eclipse.persistence.jaxb.xmlmodel.XmlAnyAttribute;
import org.eclipse.persistence.jaxb.xmlmodel.XmlAnyElement;
import org.eclipse.persistence.jaxb.xmlmodel.XmlAttribute;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.JavaTypes;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.XmlEnums;
import org.eclipse.persistence.jaxb.xmlmodel.XmlBindings.XmlRegistries;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElement;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementNillable;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementRefs;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElements;
import org.eclipse.persistence.jaxb.xmlmodel.XmlEnum;
import org.eclipse.persistence.jaxb.xmlmodel.XmlEnumValue;
import org.eclipse.persistence.jaxb.xmlmodel.XmlInverseReference;
import org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter;
import org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapters;
import org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes;
import org.eclipse.persistence.jaxb.xmlmodel.XmlMap;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNamedObjectGraph;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNsForm;
import org.eclipse.persistence.jaxb.xmlmodel.XmlNullPolicy;
import org.eclipse.persistence.jaxb.xmlmodel.XmlProperties.XmlProperty;
import org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry;
import org.eclipse.persistence.jaxb.xmlmodel.XmlSchema;
import org.eclipse.persistence.jaxb.xmlmodel.XmlSchema.XmlNs;
import org.eclipse.persistence.jaxb.xmlmodel.XmlSchemaType;
import org.eclipse.persistence.jaxb.xmlmodel.XmlSchemaTypes;
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation;
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransient;
import org.eclipse.persistence.jaxb.xmlmodel.XmlValue;
import org.eclipse.persistence.jaxb.xmlmodel.XmlVariableNode;
import org.eclipse.persistence.oxm.NamespaceResolver;
import org.eclipse.persistence.oxm.XMLNameTransformer;
/**
* INTERNAL:
* <p>
* Purpose: XMLProcessor is used to process the meta data provided
* in external OXM XML files. This information is then used in conjunction with the
* information from AnnotationsProcess to generate schemas (via SchemaGenerator)
* and mappings (via MappingsGenerator).
* </p>
*
* <p>
* As a general rule meta data provided in external OXM XML files overrides meta data
* specified through annotations.
* </p>
* @see org.eclipse.persistence.jaxb.compiler.Generator
*/
public class XMLProcessor {
private Map<String, XmlBindings> xmlBindingMap;
private JavaModelInput jModelInput;
private AnnotationsProcessor aProcessor;
private JAXBMetadataLogger logger;
private static final char COLON = ':';
private static final char SLASH = '/';
private static final String SELF = ".";
private static final char OPEN_BRACKET = '[';
private static final String IS_STR = "is";
private static final String GET_STR = "get";
private static final String SET_STR = "set";
private static final String JAVA_LANG_OBJECT = "java.lang.Object";
public static final String DEFAULT = "##default";
public static final String GENERATE = "##generate";
/**
* This is the preferred constructor.
*
*/
public XMLProcessor(Map<String, XmlBindings> bindings) {
this.xmlBindingMap = bindings;
}
/**
* Process XmlBindings on a per package basis for a given
* AnnotationsProcessor instance.
*
*/
public void processXML(AnnotationsProcessor annotationsProcessor, JavaModelInput jModelInput, TypeMappingInfo[] typeMappingInfos, JavaClass[] originalJavaClasses) {
this.jModelInput = jModelInput;
this.aProcessor = annotationsProcessor;
this.aProcessor.setHasXmlBindings(true);
Map<String, XmlEnum> xmlEnumMap = new HashMap<String, XmlEnum>();
aProcessor.init(originalJavaClasses, typeMappingInfos);
// build a map of packages to JavaClass so we only process the
// JavaClasses for a given package additional classes - i.e. ones from
// packages not listed in XML - will be processed later
Map<String, ArrayList<JavaClass>> pkgToClassMap = buildPackageToJavaClassMap();
// process each XmlBindings in the map
XmlBindings xmlBindings;
for (String packageName : xmlBindingMap.keySet()) {
ArrayList<JavaClass> classesToProcess = pkgToClassMap.get(packageName);
if (classesToProcess == null) {
getLogger().logWarning("jaxb_metadata_warning_no_classes_to_process", new Object[] { packageName });
continue;
}
xmlBindings = xmlBindingMap.get(packageName);
// handle @XmlSchema override
NamespaceInfo nsInfo = processXmlSchema(xmlBindings, packageName);
if (nsInfo != null) {
aProcessor.addPackageToNamespaceMapping(packageName, nsInfo);
}
// handle @XmlElementNillable override
if (null != xmlBindings.getXmlElementNillable()) {
aProcessor.addPackageToXmlElementNillable(packageName, xmlBindings.getXmlElementNillable());
}
// handle @XmlNullPolicy override
if (null != xmlBindings.getXmlNullPolicy()) {
aProcessor.addPackageToXmlNullPolicy(packageName, xmlBindings.getXmlNullPolicy());
}
// handle xml-registries
// add an entry to the map of registries keyed on factory class name for each
XmlRegistries xmlRegs = xmlBindings.getXmlRegistries();
if (xmlRegs != null) {
for (XmlRegistry xmlReg : xmlRegs.getXmlRegistry()) {
aProcessor.addXmlRegistry(xmlReg.getName(), xmlReg);
}
}
// build an array of JavaModel classes to process
JavaClass[] javaClasses = classesToProcess.toArray(new JavaClass[classesToProcess.size()]);
// handle xml-enums
// build a map of enum class names to XmlEnum objects
XmlEnums xmlEnums = xmlBindings.getXmlEnums();
if (xmlEnums != null) {
for (XmlEnum xmlEnum : xmlEnums.getXmlEnum()) {
xmlEnumMap.put(getQualifiedJavaTypeName(xmlEnum.getJavaEnum(), packageName), xmlEnum);
}
}
//handle superclass override
if(xmlBindings.getJavaTypes() != null) {
List<JavaType> types = xmlBindings.getJavaTypes().getJavaType();
for(JavaType next:types) {
JavaClass typeClass = jModelInput.getJavaModel().getClass(getQualifiedJavaTypeName(next.getName(), packageName));
if(typeClass != null && typeClass.getClass() == JavaClassImpl.class) {
if(next.getSuperType() != null && !(next.getSuperType().equals(DEFAULT))) {
JavaClass newSuperClass = jModelInput.getJavaModel().getClass(next.getSuperType());
((JavaClassImpl)typeClass).setSuperClassOverride(newSuperClass);
}
}
}
}
// pre-build the TypeInfo objects
Map<String, TypeInfo> typeInfoMap = aProcessor.preBuildTypeInfo(javaClasses);
// handle package-level xml-schema-types
List<XmlSchemaType> xmlSchemaTypes = null;
XmlSchemaTypes sTypes = xmlBindings.getXmlSchemaTypes();
if (sTypes != null) {
xmlSchemaTypes = sTypes.getXmlSchemaType();
} else {
xmlSchemaTypes = new ArrayList<XmlSchemaType>();
}
// handle package-level xml-schema-type
if (xmlBindings.getXmlSchemaType() != null) {
xmlSchemaTypes.add(xmlBindings.getXmlSchemaType());
}
// process each xml-schema-type entry
for (XmlSchemaType sType : xmlSchemaTypes) {
JavaClass jClass = aProcessor.getHelper().getJavaClass(sType.getType());
if (jClass != null) {
aProcessor.processSchemaType(sType.getName(), sType.getNamespace(), jClass.getQualifiedName());
}
}
PackageInfo packageInfo = aProcessor.getPackageToPackageInfoMappings().get(packageName);
if (packageInfo == null) {
packageInfo = new PackageInfo();
}
if(xmlBindings.isSetXmlAccessorType()) {
packageInfo.setAccessType(xmlBindings.getXmlAccessorType());
}
JavaTypes jTypes = xmlBindings.getJavaTypes();
if (jTypes != null) {
for (JavaType javaType : jTypes.getJavaType()) {
TypeInfo info = typeInfoMap.get(getQualifiedJavaTypeName(javaType.getName(), packageName));
// package/class override order:
// 1 - xml class-level
// 2 - java object class-level
// 3 - xml package-level
// 4 - package-info.java
// handle class-level @XmlJavaTypeAdapter override
if (javaType.getXmlJavaTypeAdapter() != null) {
info.setXmlJavaTypeAdapter(javaType.getXmlJavaTypeAdapter());
}
// handle class-level @XmlNullPolicy override
XmlNullPolicy xmlNullPolicy = javaType.getXmlNullPolicy();
if (null != xmlNullPolicy) {
info.setXmlNullPolicy(xmlNullPolicy);
}
// handle class-level @XmlElementNillable override
XmlElementNillable xmlElementNillable = javaType.getXmlElementNillable();
if (null != xmlElementNillable) {
info.setXmlElementNillable(xmlElementNillable.isNillable());
}
// handle class-level @XmlNameTransformer
String transformerClassName = javaType.getXmlNameTransformer();
XMLNameTransformer transformer = getXMLNameTransformerClassFromString(transformerClassName);
if(transformer != null){
info.setXmlNameTransformer(transformer);
}
// handle class-level @XmlExtensible override
if (javaType.getXmlVirtualAccessMethods() != null) {
info.setXmlVirtualAccessMethods(javaType.getXmlVirtualAccessMethods());
}
// handle class-level @XmlAccessorOrder override
if (javaType.isSetXmlAccessorOrder()) {
info.setXmlAccessOrder(javaType.getXmlAccessorOrder());
} else if (!info.isSetXmlAccessOrder()) {
// handle package-level @XmlAccessorOrder override
if (xmlBindings.isSetXmlAccessorOrder()) {
info.setXmlAccessOrder(xmlBindings.getXmlAccessorOrder());
} else {
// finally, check the NamespaceInfo
info.setXmlAccessOrder(packageInfo.getAccessOrder());
}
}
// handle class-level @XmlAccessorType override
if (javaType.isSetXmlAccessorType()) {
info.setXmlAccessType(javaType.getXmlAccessorType());
}
// handle @XmlInlineBinaryData override
if (javaType.isSetXmlInlineBinaryData()) {
info.setInlineBinaryData(javaType.isXmlInlineBinaryData());
}
// handle @XmlTransient override
if (javaType.isSetXmlTransient()) {
info.setXmlTransient(javaType.isXmlTransient());
}
// handle @XmlRootElement
if (javaType.getXmlRootElement() != null) {
info.setXmlRootElement(javaType.getXmlRootElement());
}
// handle @XmlSeeAlso override
if (javaType.getXmlSeeAlso() != null && javaType.getXmlSeeAlso().size() > 0) {
info.setXmlSeeAlso(javaType.getXmlSeeAlso());
}
// handle @XmlType override
if (javaType.getXmlType() != null) {
info.setXmlType(javaType.getXmlType());
}
// handle @XmlCustomizer override
if (javaType.getXmlCustomizer() != null) {
info.setXmlCustomizer(javaType.getXmlCustomizer());
}
// handle @XmlClassExtractor override
if (javaType.getXmlClassExtractor() != null) {
info.setClassExtractorName(javaType.getXmlClassExtractor().getClazz());
}
// handle @XmlProperties override
if (javaType.getXmlProperties() != null && javaType.getXmlProperties().getXmlProperty().size() > 0) {
// may need to merge with @XmlProperties (xml wins in the case of a conflict)
if (info.getUserProperties() != null) {
info.setUserProperties(mergeUserPropertyMap(javaType.getXmlProperties().getXmlProperty(), info.getUserProperties()));
} else {
info.setUserProperties(createUserPropertyMap(javaType.getXmlProperties().getXmlProperty()));
}
}
// handle @XmlDiscriminatorNode override
if (javaType.getXmlDiscriminatorNode() != null) {
info.setXmlDiscriminatorNode(javaType.getXmlDiscriminatorNode());
}
// handle @NamedObjectGraph/@NamedObjectGraphs override
if (javaType.getXmlNamedObjectGraphs() != null) {
List<XmlNamedObjectGraph> currentGraphs = info.getObjectGraphs();
for(XmlNamedObjectGraph nextGraph:javaType.getXmlNamedObjectGraphs().getXmlNamedObjectGraph()) {
//check to see if a graph with the same name already exists
//if so, remove it and replace it with the one from xml.
//if not, add the new one
for(XmlNamedObjectGraph nextExistingGraph: currentGraphs) {
if(nextGraph.getName().equals(nextExistingGraph.getName())) {
currentGraphs.remove(nextExistingGraph);
break;
}
}
}
currentGraphs.addAll(javaType.getXmlNamedObjectGraphs().getXmlNamedObjectGraph());
}
// handle @XmlDiscriminatorValue override
if (javaType.getXmlDiscriminatorValue() != null) {
info.setXmlDiscriminatorValue(javaType.getXmlDiscriminatorValue());
}
}
}
//apply package-level @XmlNameTransformer
Map<String, TypeInfo> typeInfos = aProcessor.getTypeInfosForPackage(packageName);
String transformerClassName = xmlBindings.getXmlNameTransformer();
XMLNameTransformer transformer = getXMLNameTransformerClassFromString(transformerClassName);
if(transformer != null){
packageInfo.setXmlNameTransformer(transformer);
}
// apply package-level @XmlJavaTypeAdapters
for (TypeInfo tInfo : typeInfos.values()) {
if(xmlBindings.getXmlJavaTypeAdapters() != null){
List<XmlJavaTypeAdapter> adapters = xmlBindings.getXmlJavaTypeAdapters().getXmlJavaTypeAdapter();
for (XmlJavaTypeAdapter xja : adapters) {
try {
JavaClass adapterClass = jModelInput.getJavaModel().getClass(xja.getValue());
JavaClass boundType = jModelInput.getJavaModel().getClass(xja.getType());
if (boundType != null) {
tInfo.addPackageLevelAdapterClass(adapterClass, boundType);
packageInfo.getPackageLevelAdaptersByClass().put(boundType.getQualifiedName(), adapterClass);
}
} catch(JAXBException e) {
throw JAXBException.invalidPackageAdapterClass(xja.getValue(), packageName);
}
}
}
}
}
for (String packageName : xmlBindingMap.keySet()) {
ArrayList<JavaClass> classesToProcess = pkgToClassMap.get(packageName);
if (classesToProcess == null) {
getLogger().logWarning("jaxb_metadata_warning_no_classes_to_process", new Object[] { packageName });
continue;
}
xmlBindings = xmlBindingMap.get(packageName);
JavaClass[] javaClasses = classesToProcess.toArray(new JavaClass[classesToProcess.size()]);
// post-build the TypeInfo objects
javaClasses = aProcessor.postBuildTypeInfo(javaClasses);
// get the generated TypeInfo
Map<String, TypeInfo> typeInfosForPackage = aProcessor.getTypeInfosForPackage(packageName);
// update xml-enum info if necessary
for (Entry<String, TypeInfo> entry : typeInfosForPackage.entrySet()) {
TypeInfo tInfo = entry.getValue();
if (tInfo.isEnumerationType()) {
EnumTypeInfo etInfo = (EnumTypeInfo) tInfo;
XmlEnum xmlEnum = xmlEnumMap.get(etInfo.getClassName());
if (xmlEnum != null) {
JavaClass restrictionClass = aProcessor.getHelper().getJavaClass(xmlEnum.getValue());
// default to String if necessary
if (restrictionClass == null) {
restrictionClass = jModelInput.getJavaModel().getClass(String.class);
}
etInfo.setRestrictionBase(aProcessor.getSchemaTypeFor(restrictionClass));
for (XmlEnumValue xmlEnumValue : xmlEnum.getXmlEnumValue()) {
// overwrite any existing entries (from annotations)
etInfo.addJavaFieldToXmlEnumValuePair(true, xmlEnumValue.getJavaEnumValue(), xmlEnumValue.getValue());
}
}
}
}
// update TypeInfo objects based on the JavaTypes
JavaTypes jTypes = xmlBindings.getJavaTypes();
if (jTypes != null) {
PackageInfo packageInfo = aProcessor.getPackageToPackageInfoMappings().get(packageName);
NamespaceInfo nsInfo = null;
if(null != packageInfo) {
nsInfo = packageInfo.getNamespaceInfo();
}
for (JavaType javaType : jTypes.getJavaType()) {
processJavaType(javaType, typeInfosForPackage.get(getQualifiedJavaTypeName(javaType.getName(), packageName)), nsInfo);
}
}
// remove the entry for this package from the map
pkgToClassMap.remove(packageName);
}
// now process remaining classes
Iterator<ArrayList<JavaClass>> classIt = pkgToClassMap.values().iterator();
while (classIt.hasNext()) {
ArrayList<JavaClass> jClassList = classIt.next();
JavaClass[] jClassArray = jClassList.toArray(new JavaClass[jClassList.size()]);
aProcessor.buildNewTypeInfo(jClassArray);
aProcessor.checkForCallbackMethods();
}
// need to ensure that any bound types (from XmlJavaTypeAdapter) have TypeInfo
// objects built for them - SchemaGenerator will require a descriptor for each
Map<String, TypeInfo> typeInfos = (Map<String, TypeInfo>) ((HashMap)aProcessor.getTypeInfos()).clone();
for (Entry<String, TypeInfo> entry : typeInfos.entrySet()) {
JavaClass[] jClassArray;
for (Property prop : entry.getValue().getPropertyList()) {
if (prop.isSetXmlJavaTypeAdapter()) {
jClassArray = new JavaClass[] { prop.getActualType() };
aProcessor.buildNewTypeInfo(jClassArray);
}
}
}
// now trigger the annotations processor to process the classes
List<JavaClass> jClasses = aProcessor.getTypeInfoClasses();
// If multiple bindings (packages) are supplied, re-process super classes
// (in case super and sub classes were in different packages)
if (xmlBindingMap.size() > 1) {
for (JavaClass c : jClasses) {
TypeInfo ti = aProcessor.getTypeInfos().get(c.getQualifiedName());
aProcessor.processPropertiesSuperClass(c, ti);
}
}
aProcessor.processPropertyTypes(jClasses.toArray(new JavaClass[jClasses.size()]));
aProcessor.finalizeProperties();
aProcessor.createElementsForTypeMappingInfo();
aProcessor.checkForCallbackMethods();
}
private XMLNameTransformer getXMLNameTransformerClassFromString(String transformerClassName){
XMLNameTransformer transformer = null;
if(transformerClassName != null){
Class nameTransformerClass;
try {
nameTransformerClass = Class.forName(transformerClassName);
} catch (ClassNotFoundException ex) {
throw JAXBException.exceptionWithNameTransformerClass(transformerClassName, ex);
}
try {
transformer = (XMLNameTransformer) nameTransformerClass.getConstructor().newInstance();
} catch (ReflectiveOperationException ex) {
throw JAXBException.exceptionWithNameTransformerClass(transformerClassName, ex);
}
}
return transformer;
}
/**
* Process a given JavaType's attributes.
*
*/
private void processJavaType(JavaType javaType, TypeInfo typeInfo, NamespaceInfo nsInfo) {
// process field/property overrides
if (null != javaType.getJavaAttributes()) {
List<String> processedPropertyNames = new ArrayList<String>();
for (JAXBElement jaxbElement : javaType.getJavaAttributes().getJavaAttribute()) {
JavaAttribute javaAttribute = (JavaAttribute) jaxbElement.getValue();
Property originalProperty = typeInfo.getOriginalProperties().get(javaAttribute.getJavaAttribute());
if(javaAttribute.getXmlAccessorType() != null) {
originalProperty = processPropertyForAccessorType(typeInfo, javaAttribute, originalProperty);
}
if (originalProperty == null) {
if (typeInfo.getXmlVirtualAccessMethods() != null) {
Property newProperty = new Property(this.aProcessor.getHelper());
newProperty.setPropertyName(javaAttribute.getJavaAttribute());
newProperty.setExtension(true);
String attributeType = null;
if (javaAttribute instanceof XmlElement) {
attributeType = ((XmlElement) javaAttribute).getType();
} else if (javaAttribute instanceof XmlAttribute) {
attributeType = ((XmlAttribute) javaAttribute).getType();
}
if (attributeType != null && attributeType.equals("DEFAULT")) {
newProperty.setType(jModelInput.getJavaModel().getClass(attributeType));
} else {
newProperty.setType(jModelInput.getJavaModel().getClass(Helper.STRING));
}
originalProperty = newProperty;
typeInfo.addProperty(javaAttribute.getJavaAttribute(), newProperty);
} else {
getLogger().logWarning(JAXBMetadataLogger.NO_PROPERTY_FOR_JAVA_ATTRIBUTE, new Object[] { javaAttribute.getJavaAttribute(), javaType.getName() });
continue;
}
}
boolean alreadyProcessed = processedPropertyNames.contains(javaAttribute.getJavaAttribute());
Property propToProcess;
// In the case where there is more than one javaAttribute for the same Property
// (multiple mappings to same attribute) clone the original and put it in a
// separate Map; otherwise, update the property as per usual
if (alreadyProcessed) {
propToProcess = (Property) originalProperty.clone();
} else {
propToProcess = typeInfo.getProperties().get(javaAttribute.getJavaAttribute());
}
processJavaAttribute(typeInfo, javaAttribute, propToProcess, nsInfo, javaType);
// (Bug 346081) if discover a transient attribute apply same behavior as transient annotation and remove
if(propToProcess.isTransient()){
typeInfo.getPropertyList().remove(propToProcess);
}
// if we are dealing with multiple mappings for the same attribute, leave the existing
// property as-is and update the additionalProperties list on the owning TypeInfo
if (alreadyProcessed) {
List<Property> additionalProps = null;
if(typeInfo.hasAdditionalProperties()) {
additionalProps = typeInfo.getAdditionalProperties().get(javaAttribute.getJavaAttribute());
}
if (additionalProps == null) {
additionalProps = new ArrayList<Property>();
}
additionalProps.add(propToProcess);
typeInfo.getAdditionalProperties().put(javaAttribute.getJavaAttribute(), additionalProps);
} else {
// single mapping case; update the TypeInfo as per usual
typeInfo.getProperties().put(javaAttribute.getJavaAttribute(), propToProcess);
// keep track of processed property names
processedPropertyNames.add(javaAttribute.getJavaAttribute());
}
}
}
}
private Property processPropertyForAccessorType(TypeInfo typeInfo, JavaAttribute javaAttribute, Property originalProperty) {
if(originalProperty == null) {
Property prop = createProperty(typeInfo, javaAttribute);
if(prop != null) {
typeInfo.addProperty(prop.getPropertyName(), prop);
}
return prop;
}
if((javaAttribute.getXmlAccessorType() == XmlAccessType.FIELD && !(originalProperty.isMethodProperty())) ||
javaAttribute.getXmlAccessorType() == XmlAccessType.PROPERTY && originalProperty.isMethodProperty()) {
return originalProperty;
}
originalProperty.setMethodProperty(!(originalProperty.isMethodProperty()));
if(originalProperty.isMethodProperty()) {
//figure out get and set method names. See if they exist.
JavaClass jClass = this.jModelInput.getJavaModel().getClass(typeInfo.getJavaClassName());
String propName = originalProperty.getPropertyName();
propName = Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
String getMethodName = GET_STR + propName;
String setMethodName = SET_STR + propName;
JavaMethod getMethod = jClass.getDeclaredMethod(getMethodName, new JavaClass[]{});
if(getMethod == null) {
getMethodName = IS_STR + propName;
getMethod = jClass.getDeclaredMethod(getMethodName, new JavaClass[]{});
}
JavaMethod setMethod = jClass.getDeclaredMethod(setMethodName, new JavaClass[]{originalProperty.getType()});
if(getMethod != null) {
originalProperty.setGetMethodName(getMethodName);
}
if(setMethod != null) {
originalProperty.setSetMethodName(setMethodName);
}
} else {
originalProperty.setGetMethodName(null);
originalProperty.setSetMethodName(null);
originalProperty.setMethodProperty(false);
}
return originalProperty;
}
private Property createProperty(TypeInfo info, JavaAttribute javaAttribute) {
XmlAccessType xmlAccessorType = javaAttribute.getXmlAccessorType();
//Property prop = new Property();
//prop.setPropertyName(javaAttribute.getJavaAttribute());
String propName = javaAttribute.getJavaAttribute();
JavaHasAnnotations element = null;
JavaClass pType = null;
JavaClass jClass = this.jModelInput.getJavaModel().getClass(info.getJavaClassName());
if(xmlAccessorType == XmlAccessType.PROPERTY) {
//set up accessor method names
String name = Character.toUpperCase(propName.charAt(0)) + propName.substring(1);
String getMethodName = GET_STR + name;
String setMethodName = SET_STR + name;
JavaMethod jMethod = jClass.getDeclaredMethod(getMethodName, new JavaClass[]{});
if(jMethod == null) {
getMethodName = IS_STR + name;
jMethod = jClass.getDeclaredMethod(getMethodName, new JavaClass[]{});
}
if(jMethod != null) {
pType = jMethod.getReturnType();
element = jMethod;
} else {
//look for a set method if type is set on javaAttribute
for (Object next:jClass.getDeclaredMethods()) {
JavaMethod nextMethod = (JavaMethod)next;
if(nextMethod.getName().equals(setMethodName) && nextMethod.getParameterTypes().length == 1) {
pType = nextMethod.getParameterTypes()[0];
element = nextMethod;
}
}
if(element == null) {
return null;
}
}
} else {
JavaField jField = jClass.getDeclaredField(propName);
if(jField == null) {
return null;
}
pType = jField.getResolvedType();
element = jField;
}
return this.aProcessor.buildNewProperty(info, jClass, element, propName, pType);
}
/**
* Process a given JavaAtribute.
*
*/
private Property processJavaAttribute(TypeInfo typeInfo, JavaAttribute javaAttribute, Property oldProperty, NamespaceInfo nsInfo, JavaType javaType) {
if (javaAttribute instanceof XmlVariableNode) {
return processXmlVariableNodeAttribute((XmlVariableNode) javaAttribute, oldProperty, typeInfo, javaType);
}
if (javaAttribute instanceof XmlAnyAttribute) {
return processXmlAnyAttribute((XmlAnyAttribute) javaAttribute, oldProperty, typeInfo, javaType);
}
if (javaAttribute instanceof XmlAnyElement) {
return processXmlAnyElement((XmlAnyElement) javaAttribute, oldProperty, typeInfo, javaType);
}
if (javaAttribute instanceof XmlAttribute) {
return processXmlAttribute((XmlAttribute) javaAttribute, oldProperty, typeInfo, nsInfo, javaType);
}
if (javaAttribute instanceof XmlElement) {
return processXmlElement((XmlElement) javaAttribute, oldProperty, typeInfo, nsInfo, javaType);
}
if (javaAttribute instanceof XmlElements) {
return processXmlElements((XmlElements) javaAttribute, oldProperty, typeInfo);
}
if (javaAttribute instanceof XmlElementRef) {
return processXmlElementRef((XmlElementRef) javaAttribute, oldProperty, typeInfo);
}
if (javaAttribute instanceof XmlElementRefs) {
return processXmlElementRefs((XmlElementRefs) javaAttribute, oldProperty, typeInfo);
}
if (javaAttribute instanceof XmlTransient) {
return processXmlTransient((XmlTransient) javaAttribute, oldProperty);
}
if (javaAttribute instanceof XmlValue) {
return processXmlValue((XmlValue) javaAttribute, oldProperty, typeInfo, javaType);
}
if (javaAttribute instanceof XmlJavaTypeAdapter) {
return processXmlJavaTypeAdapter((XmlJavaTypeAdapter) javaAttribute, oldProperty);
}
if (javaAttribute instanceof XmlInverseReference) {
return processXmlInverseReference((XmlInverseReference)javaAttribute, oldProperty, typeInfo);
}
if (javaAttribute instanceof XmlTransformation) {
return processXmlTransformation((XmlTransformation)javaAttribute, oldProperty, typeInfo);
}
if (javaAttribute instanceof XmlJoinNodes) {
return processXmlJoinNodes((XmlJoinNodes) javaAttribute, oldProperty, typeInfo);
}
getLogger().logWarning("jaxb_metadata_warning_invalid_java_attribute", new Object[] { javaAttribute.getClass() });
return null;
}
/**
* Handle property-level XmlJavaTypeAdapter
*
*/
private Property processXmlJavaTypeAdapter(XmlJavaTypeAdapter xmlAdapter, Property oldProperty) {
oldProperty.setXmlJavaTypeAdapter(xmlAdapter);
return oldProperty;
}
/**
* Handle xml-inverse-reference.
*
*/
private Property processXmlInverseReference(XmlInverseReference xmlInverseReference, Property oldProperty, TypeInfo info) {
resetProperty(oldProperty, info);
oldProperty.setInverseReference(true, false);
oldProperty.setInverseReferencePropertyName(xmlInverseReference.getMappedBy());
if (xmlInverseReference.getXmlAccessMethods() != null) {
oldProperty.setInverseReferencePropertyGetMethodName(xmlInverseReference.getXmlAccessMethods().getGetMethod());
oldProperty.setInverseReferencePropertySetMethodName(xmlInverseReference.getXmlAccessMethods().getSetMethod());
}
// set user-defined properties
if (xmlInverseReference.getXmlProperties() != null && xmlInverseReference.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlInverseReference.getXmlProperties().getXmlProperty()));
}
// check for container type
if (!xmlInverseReference.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlInverseReference.getContainerType());
}
// set type
if (!xmlInverseReference.getType().equals(DEFAULT)) {
JavaClass pType = jModelInput.getJavaModel().getClass(xmlInverseReference.getType());
if (aProcessor.getHelper().isCollectionType(oldProperty.getType())) {
oldProperty.setGenericType(pType);
} else {
oldProperty.setType(pType);
}
oldProperty.setHasXmlElementType(true);
// may need to generate a type info for the type
if (aProcessor.shouldGenerateTypeInfo(pType) && aProcessor.getTypeInfos().get(pType.getQualifiedName()) == null) {
aProcessor.buildNewTypeInfo(new JavaClass[] { pType });
}
}
return oldProperty;
}
/**
* Handle xml-any-attribute.
*
*/
private Property processXmlAnyAttribute(XmlAnyAttribute xmlAnyAttribute, Property oldProperty, TypeInfo tInfo, JavaType javaType) {
// if oldProperty is already an Any (via @XmlAnyAttribute annotation)
// there's nothing to do
if (oldProperty.isAnyAttribute()) {
return oldProperty;
}
// type has to be a java.util.Map
if (!aProcessor.getHelper().isMapType(oldProperty.getType())) {
if (oldProperty.getType().getClass().getName().contains("OXMJavaClassImpl")) {
JavaClass pType = jModelInput.getJavaModel().getClass("java.util.Map");
oldProperty.setType(pType);
} else {
throw org.eclipse.persistence.exceptions.JAXBException.anyAttributeOnNonMap(oldProperty.getPropertyName());
}
}
// reset any existing values
resetProperty(oldProperty, tInfo);
oldProperty.setIsAnyAttribute(true);
tInfo.setAnyAttributePropertyName(oldProperty.getPropertyName());
// handle XmlPath
if (xmlAnyAttribute.getXmlPath() != null) {
oldProperty.setXmlPath(xmlAnyAttribute.getXmlPath());
}
// handle get/set methods
if (xmlAnyAttribute.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlAnyAttribute.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlAnyAttribute.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlAnyAttribute.isSetReadOnly()) {
oldProperty.setReadOnly(xmlAnyAttribute.isReadOnly());
}
// handle write-only
if (xmlAnyAttribute.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlAnyAttribute.isWriteOnly());
}
// set user-defined properties
if (xmlAnyAttribute.getXmlProperties() != null && xmlAnyAttribute.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlAnyAttribute.getXmlProperties().getXmlProperty()));
}
// check for container type
if (!xmlAnyAttribute.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlAnyAttribute.getContainerType());
}
return oldProperty;
}
private Property processXmlVariableNodeAttribute(XmlVariableNode xmlVariableNode, Property oldProperty, TypeInfo tInfo, JavaType javaType) {
processObjectFactory(tInfo);
// reset any existing values
resetProperty(oldProperty, tInfo);
oldProperty.setVariableAttributeName(xmlVariableNode.getJavaVariableAttribute());
String type = xmlVariableNode.getType();
if(!type.equals(DEFAULT)){
oldProperty.setVariableClassName(type);
}
if (xmlVariableNode.getXmlPath() != null) {
oldProperty.setXmlPath(xmlVariableNode.getXmlPath());
} else {
// no xml-path, so use name/namespace from xml-element, and process wrapper
XmlElementWrapper xmlElementWrapper = xmlVariableNode.getXmlElementWrapper();
if (xmlElementWrapper != null) {
if (DEFAULT.equals(xmlElementWrapper.getName())) {
xmlElementWrapper.setName(tInfo.getXmlNameTransformer().transformElementName(oldProperty.getPropertyName()));
}
oldProperty.setXmlElementWrapper(xmlVariableNode.getXmlElementWrapper());
}
}
return oldProperty;
}
/**
* Handle xml-any-element. If the property was annotated with @XmlAnyElement
* in code all values will be overridden.
*
*/
private Property processXmlAnyElement(XmlAnyElement xmlAnyElement, Property oldProperty, TypeInfo tInfo, JavaType javaType) {
processObjectFactory(tInfo);
// reset any existing values
resetProperty(oldProperty, tInfo);
// set xml-any-element specific properties
oldProperty.setIsAny(true);
oldProperty.setDomHandlerClassName(xmlAnyElement.getDomHandler());
oldProperty.setLax(xmlAnyElement.isLax());
oldProperty.setMixedContent(xmlAnyElement.isXmlMixed());
oldProperty.setXmlJavaTypeAdapter(xmlAnyElement.getXmlJavaTypeAdapter());
// update TypeInfo
tInfo.setMixed(xmlAnyElement.isXmlMixed());
tInfo.setAnyElementPropertyName(oldProperty.getPropertyName());
// handle XmlPath
if (xmlAnyElement.getXmlPath() != null) {
oldProperty.setXmlPath(xmlAnyElement.getXmlPath());
}
// handle get/set methods
if (xmlAnyElement.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlAnyElement.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlAnyElement.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlAnyElement.isSetReadOnly()) {
oldProperty.setReadOnly(xmlAnyElement.isReadOnly());
}
// handle write-only
if (xmlAnyElement.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlAnyElement.isWriteOnly());
}
// set user-defined properties
if (xmlAnyElement.getXmlProperties() != null && xmlAnyElement.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlAnyElement.getXmlProperties().getXmlProperty()));
}
// check for container type
if (!xmlAnyElement.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlAnyElement.getContainerType());
}
// check for xml-element-refs
if (xmlAnyElement.getXmlElementRefs() != null) {
oldProperty.setXmlElementRefs(xmlAnyElement.getXmlElementRefs().getXmlElementRef());
oldProperty.setIsReference(true);
boolean required = true;
for (XmlElementRef eltRef : xmlAnyElement.getXmlElementRefs().getXmlElementRef()) {
required = required && eltRef.isRequired();
}
oldProperty.setIsRequired(required);
if (xmlAnyElement.getXmlElementRefs().isSetXmlMixed()) {
oldProperty.setMixedContent(xmlAnyElement.getXmlElementRefs().isXmlMixed());
}
}
return oldProperty;
}
/**
* XmlAttribute override will completely replace the existing values.
*
*/
private Property processXmlAttribute(XmlAttribute xmlAttribute, Property oldProperty, TypeInfo typeInfo, NamespaceInfo nsInfo, JavaType javaType) {
// reset any existing values
resetProperty(oldProperty, typeInfo);
// handle xml-id
if (xmlAttribute.isXmlId()) {
oldProperty.setIsXmlId(true);
oldProperty.setIsXmlIdExtension(true);
typeInfo.setIDProperty(oldProperty);
} else {
// account for XmlID un-set via XML
if (typeInfo.getIDProperty() != null && typeInfo.getIDProperty().getPropertyName().equals(oldProperty.getPropertyName())) {
typeInfo.setIDProperty(null);
}
}
// handle xml-idref
oldProperty.setIsXmlIdRef(xmlAttribute.isXmlIdref());
// handle xml-key
if (xmlAttribute.isXmlKey()) {
typeInfo.addXmlKeyProperty(oldProperty);
}
// set isAttribute
oldProperty.setIsAttribute(true);
// set xml-inline-binary-data
oldProperty.setisInlineBinaryData(xmlAttribute.isXmlInlineBinaryData());
String name;
String namespace;
// handle XmlPath
// if xml-path is set, we ignore name/namespace
if (xmlAttribute.getXmlPath() != null) {
oldProperty.setXmlPath(xmlAttribute.getXmlPath());
name = getNameFromXPath(xmlAttribute.getXmlPath(), oldProperty.getPropertyName(), true);
namespace = DEFAULT;
} else {
// no xml-path, so use name/namespace from xml-attribute
name = xmlAttribute.getName();
namespace = xmlAttribute.getNamespace();
}
if (javaType.getXmlType() != null && javaType.getXmlType().getNamespace() != null &&
(xmlAttribute.getNamespace() != null && xmlAttribute.getNamespace().equals(DEFAULT))) {
// Inherit type-level namespace if there is one
namespace = javaType.getXmlType().getNamespace();
}
// set schema name
QName qName;
if (name.equals(DEFAULT)) {
name = typeInfo.getXmlNameTransformer().transformAttributeName(oldProperty.getPropertyName());
}
if (namespace.equals(DEFAULT)) {
if (nsInfo.isAttributeFormQualified()) {
qName = new QName(nsInfo.getNamespace(), name);
} else {
qName = new QName(name);
}
} else {
qName = new QName(namespace, name);
}
oldProperty.setSchemaName(qName);
// check for container type
if (!xmlAttribute.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlAttribute.getContainerType());
}
// set type
if (!xmlAttribute.getType().equals(DEFAULT)) {
JavaClass pType = jModelInput.getJavaModel().getClass(xmlAttribute.getType());
if (aProcessor.getHelper().isCollectionType(oldProperty.getType())) {
oldProperty.setGenericType(pType);
} else {
oldProperty.setType(pType);
}
oldProperty.setHasXmlElementType(true);
// may need to generate a type info for the type
if (aProcessor.shouldGenerateTypeInfo(pType) && aProcessor.getTypeInfos().get(pType.getQualifiedName()) == null) {
aProcessor.buildNewTypeInfo(new JavaClass[] { pType });
}
}
reapplyPackageAndClassAdapters(oldProperty, typeInfo);
// handle XmlJavaTypeAdapter
if (xmlAttribute.getXmlJavaTypeAdapter() != null) {
oldProperty.setXmlJavaTypeAdapter(xmlAttribute.getXmlJavaTypeAdapter());
}
// handle required - for required, if set by user than true/false;
// if not set by user, true if property type == primitive
if (xmlAttribute.isSetRequired()) {
oldProperty.setIsRequired(xmlAttribute.isRequired());
} else if (oldProperty.getActualType().isPrimitive()) {
oldProperty.setIsRequired(true);
}
// handle xml-mime-type
if (xmlAttribute.getXmlMimeType() != null) {
oldProperty.setMimeType(xmlAttribute.getXmlMimeType());
}
// handle xml-attachment-ref
if (xmlAttribute.isXmlAttachmentRef()) {
oldProperty.setIsSwaAttachmentRef(true);
oldProperty.setSchemaType(Constants.SWA_REF_QNAME);
} else if (aProcessor.isMtomAttachment(oldProperty)) {
oldProperty.setIsMtomAttachment(true);
oldProperty.setSchemaType(Constants.BASE_64_BINARY_QNAME);
}
// handle xml-schema-type
if (xmlAttribute.getXmlSchemaType() != null) {
oldProperty.setSchemaType(new QName(xmlAttribute.getXmlSchemaType().getNamespace(), xmlAttribute.getXmlSchemaType().getName()));
}
// handle get/set methods
if (xmlAttribute.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlAttribute.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlAttribute.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlAttribute.isSetReadOnly()) {
oldProperty.setReadOnly(xmlAttribute.isReadOnly());
}
// handle write-only
if (xmlAttribute.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlAttribute.isWriteOnly());
}
// handle null policy
if (xmlAttribute.getXmlAbstractNullPolicy() != null) {
JAXBElement<? extends XmlAbstractNullPolicy> jaxbElt = xmlAttribute.getXmlAbstractNullPolicy();
oldProperty.setNullPolicy(jaxbElt.getValue());
}
// set user-defined properties
if (xmlAttribute.getXmlProperties() != null && xmlAttribute.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlAttribute.getXmlProperties().getXmlProperty()));
}
return oldProperty;
}
/**
* XmlElement override will completely replace the existing values.
*
*/
private Property processXmlElement(XmlElement xmlElement, Property oldProperty, TypeInfo typeInfo, NamespaceInfo nsInfo, JavaType javaType) {
// reset any existing values
resetProperty(oldProperty, typeInfo);
if (xmlElement.getXmlMap() != null) {
processXmlMap(xmlElement.getXmlMap(), oldProperty);
}
if (xmlElement.isXmlLocation()) {
if (!aProcessor.getHelper().getJavaClass(Constants.LOCATOR_CLASS).isAssignableFrom(oldProperty.getType())) {
throw JAXBException.invalidXmlLocation(oldProperty.getPropertyName(), oldProperty.getType().getName());
}
oldProperty.setXmlLocation(true);
}
// handle xml-id
if (xmlElement.isXmlId()) {
oldProperty.setIsXmlId(true);
oldProperty.setIsXmlIdExtension(true);
typeInfo.setIDProperty(oldProperty);
} else {
// account for XmlID un-set via XML
if (typeInfo.getIDProperty() != null && typeInfo.getIDProperty().getPropertyName().equals(oldProperty.getPropertyName())) {
typeInfo.setIDProperty(null);
}
}
if(xmlElement.getXmlInverseReference() != null){
String mappedBy = xmlElement.getXmlInverseReference().getMappedBy();
oldProperty.setInverseReference(true, true);
oldProperty.setInverseReferencePropertyName(mappedBy);
}
// handle xml-idref
oldProperty.setIsXmlIdRef(xmlElement.isXmlIdref());
// handle xml-key
if (xmlElement.isXmlKey()) {
typeInfo.addXmlKeyProperty(oldProperty);
}
// set required
oldProperty.setIsRequired(xmlElement.isRequired());
// set xml-inline-binary-data
oldProperty.setisInlineBinaryData(xmlElement.isXmlInlineBinaryData());
// set nillable
oldProperty.setNillable(xmlElement.isNillable());
// set defaultValue
if (xmlElement.getDefaultValue().equals("\u0000")) {
oldProperty.setDefaultValue(null);
} else {
oldProperty.setDefaultValue(xmlElement.getDefaultValue());
}
String name;
String namespace;
// handle XmlPath / XmlElementWrapper
// if xml-path is set, we ignore xml-element-wrapper, as well as name/namespace on xml-element
if (xmlElement.getXmlPath() != null) {
oldProperty.setXmlPath(xmlElement.getXmlPath());
name = getNameFromXPath(xmlElement.getXmlPath(), oldProperty.getPropertyName(), false);
namespace = DEFAULT;
} else {
// no xml-path, so use name/namespace from xml-element, and process wrapper
name = xmlElement.getName();
namespace = xmlElement.getNamespace();
XmlElementWrapper xmlElementWrapper = xmlElement.getXmlElementWrapper();
if (xmlElementWrapper != null) {
if (DEFAULT.equals(xmlElementWrapper.getName())) {
xmlElementWrapper.setName(typeInfo.getXmlNameTransformer().transformElementName(oldProperty.getPropertyName()));
}
oldProperty.setXmlElementWrapper(xmlElement.getXmlElementWrapper());
if(oldProperty.isMap()){
name = xmlElement.getXmlElementWrapper().getName();
namespace = xmlElement.getXmlElementWrapper().getNamespace();
}
}
}
if (javaType.getXmlType() != null && javaType.getXmlType().getNamespace() != null &&
(xmlElement.getNamespace() != null && xmlElement.getNamespace().equals(DEFAULT))) {
// Inherit type-level namespace if there is one
namespace = javaType.getXmlType().getNamespace();
}
// set schema name
QName qName;
if (name.equals(DEFAULT)) {
name = typeInfo.getXmlNameTransformer().transformElementName(oldProperty.getPropertyName());
}
if (namespace.equals(DEFAULT)) {
if (nsInfo.isElementFormQualified()) {
qName = new QName(nsInfo.getNamespace(), name);
} else {
qName = new QName(name);
}
} else {
qName = new QName(namespace, name);
}
oldProperty.setSchemaName(qName);
// check for container type
if (!xmlElement.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlElement.getContainerType());
}
// set type
if (xmlElement.getType().equals("jakarta.xml.bind.annotation.XmlElement.DEFAULT")) {
// if xmlElement has no type, and the property type was set via
// @XmlElement, reset it to the original value
if (oldProperty.isXmlElementType()) {
oldProperty.setType(oldProperty.getOriginalType());
}
} else if (xmlElement.getXmlMap() != null) {
getLogger().logWarning(JAXBMetadataLogger.INVALID_TYPE_ON_MAP, new Object[] { xmlElement.getName() });
} else {
JavaClass pType = jModelInput.getJavaModel().getClass(xmlElement.getType());
if(aProcessor.getHelper().isCollectionType(oldProperty.getType())) {
oldProperty.setGenericType(pType);
} else {
oldProperty.setType(pType);
}
oldProperty.setHasXmlElementType(true);
// may need to generate a type info for the type
if (aProcessor.shouldGenerateTypeInfo(pType) && aProcessor.getTypeInfos().get(pType.getQualifiedName()) == null) {
aProcessor.buildNewTypeInfo(new JavaClass[] { pType });
}
}
reapplyPackageAndClassAdapters(oldProperty, typeInfo);
// handle XmlJavaTypeAdapter
if (xmlElement.getXmlJavaTypeAdapter() != null) {
try {
oldProperty.setXmlJavaTypeAdapter(xmlElement.getXmlJavaTypeAdapter());
} catch(JAXBException e) {
throw JAXBException.invalidPropertyAdapterClass(xmlElement.getXmlJavaTypeAdapter().getValue(), xmlElement.getJavaAttribute(), javaType.getName());
}
}
// for primitives we always set required, a.k.a. minOccurs="1"
if (!oldProperty.isRequired()) {
JavaClass ptype = oldProperty.getActualType();
oldProperty.setIsRequired(ptype.isPrimitive() || ptype.isArray() && ptype.getComponentType().isPrimitive());
}
// handle xml-list
if (xmlElement.isSetXmlList()) {
// Make sure XmlList annotation is on a collection or array
if (!aProcessor.getHelper().isCollectionType(oldProperty.getType()) && !oldProperty.getType().isArray()) {
throw JAXBException.invalidList(oldProperty.getPropertyName());
}
oldProperty.setIsXmlList(xmlElement.isXmlList());
}
// handle xml-mime-type
if (xmlElement.getXmlMimeType() != null) {
oldProperty.setMimeType(xmlElement.getXmlMimeType());
}
// handle xml-attachment-ref
if (xmlElement.isXmlAttachmentRef()) {
oldProperty.setIsSwaAttachmentRef(true);
oldProperty.setSchemaType(Constants.SWA_REF_QNAME);
} else if (aProcessor.isMtomAttachment(oldProperty)) {
oldProperty.setIsMtomAttachment(true);
oldProperty.setSchemaType(Constants.BASE_64_BINARY_QNAME);
}
// handle xml-schema-type
if (xmlElement.getXmlSchemaType() != null) {
oldProperty.setSchemaType(new QName(xmlElement.getXmlSchemaType().getNamespace(), xmlElement.getXmlSchemaType().getName()));
}
// handle get/set methods
if (xmlElement.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlElement.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlElement.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlElement.isSetReadOnly()) {
oldProperty.setReadOnly(xmlElement.isReadOnly());
}
// handle write-only
if (xmlElement.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlElement.isWriteOnly());
}
// handle cdata
if (xmlElement.isSetCdata()) {
oldProperty.setCdata(xmlElement.isCdata());
}
// handle null policy
if (xmlElement.getXmlAbstractNullPolicy() != null) {
JAXBElement<? extends XmlAbstractNullPolicy> jaxbElt = xmlElement.getXmlAbstractNullPolicy();
oldProperty.setNullPolicy(jaxbElt.getValue());
}
// set user-defined properties
if (xmlElement.getXmlProperties() != null && xmlElement.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlElement.getXmlProperties().getXmlProperty()));
}
return oldProperty;
}
private Property processXmlMap(XmlMap xmlMap, Property oldProperty) {
XmlMap.Key mapKey = xmlMap.getKey();
XmlMap.Value mapValue = xmlMap.getValue();
if (mapKey != null && mapKey.getType() != null) {
oldProperty.setKeyType(jModelInput.getJavaModel().getClass(mapKey.getType()));
} else {
oldProperty.setKeyType(jModelInput.getJavaModel().getClass(JAVA_LANG_OBJECT));
}
if (mapValue != null && mapValue.getType() != null) {
oldProperty.setValueType(jModelInput.getJavaModel().getClass(mapValue.getType()));
} else {
oldProperty.setValueType(jModelInput.getJavaModel().getClass(JAVA_LANG_OBJECT));
}
return oldProperty;
}
/**
* Process XmlElements.
*
* The XmlElements object will be set on the property, and it will be
* flagged as a 'choice'.
*
*/
private Property processXmlElements(XmlElements xmlElements, Property oldProperty, TypeInfo tInfo) {
resetProperty(oldProperty, tInfo);
oldProperty.setChoice(true);
oldProperty.setXmlElements(xmlElements);
// handle idref
oldProperty.setIsXmlIdRef(xmlElements.isXmlIdref());
// handle XmlElementWrapper
if (xmlElements.getXmlElementWrapper() != null) {
oldProperty.setXmlElementWrapper(xmlElements.getXmlElementWrapper());
}
// handle get/set methods
if (xmlElements.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlElements.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlElements.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlElements.isSetReadOnly()) {
oldProperty.setReadOnly(xmlElements.isReadOnly());
}
// handle write-only
if (xmlElements.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlElements.isWriteOnly());
}
// set user-defined properties
if (xmlElements.getXmlProperties() != null && xmlElements.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlElements.getXmlProperties().getXmlProperty()));
}
// check for container type
if (!xmlElements.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlElements.getContainerType());
}
// check for xml-join-nodes
if (xmlElements.hasXmlJoinNodes()) {
// store the List of XmlJoinNodes so we can access them when
// we process the choice elements in AnnotationsProcessor
oldProperty.setXmlJoinNodesList(xmlElements.getXmlJoinNodes());
}
// handle XmlJavaTypeAdapter
if (xmlElements.getXmlJavaTypeAdapter() != null) {
try {
oldProperty.setXmlJavaTypeAdapter(xmlElements.getXmlJavaTypeAdapter());
} catch(JAXBException e) {
throw JAXBException.invalidPropertyAdapterClass(xmlElements.getXmlJavaTypeAdapter().getValue(), xmlElements.getJavaAttribute(), tInfo.getJavaClassName());
}
}
return oldProperty;
}
/**
* Process an xml-element-ref.
*
*/
private Property processXmlElementRef(XmlElementRef xmlElementRef, Property oldProperty, TypeInfo info) {
processObjectFactory(info);
resetProperty(oldProperty, info);
List<XmlElementRef> eltRefs = new ArrayList<XmlElementRef>();
eltRefs.add(xmlElementRef);
oldProperty.setXmlElementRefs(eltRefs);
oldProperty.setIsReference(true);
oldProperty.setIsRequired(xmlElementRef.isRequired());
// handle XmlAdapter
if (xmlElementRef.getXmlJavaTypeAdapter() != null) {
oldProperty.setXmlJavaTypeAdapter(xmlElementRef.getXmlJavaTypeAdapter());
}
// check for container type
if (!xmlElementRef.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlElementRef.getContainerType());
}
// handle XmlElementWrapper
if (xmlElementRef.getXmlElementWrapper() != null) {
oldProperty.setXmlElementWrapper(xmlElementRef.getXmlElementWrapper());
}
// set user-defined properties
if (xmlElementRef.getXmlProperties() != null && xmlElementRef.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlElementRef.getXmlProperties().getXmlProperty()));
}
if (xmlElementRef.isSetXmlMixed()) {
oldProperty.setMixedContent(xmlElementRef.isXmlMixed());
}
// handle get/set methods
if (xmlElementRef.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlElementRef.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlElementRef.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlElementRef.isSetReadOnly()) {
oldProperty.setReadOnly(xmlElementRef.isReadOnly());
}
// handle write-only
if (xmlElementRef.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlElementRef.isWriteOnly());
}
return oldProperty;
}
/**
* Process an xml-element-refs.
*
*/
private Property processXmlElementRefs(XmlElementRefs xmlElementRefs, Property oldProperty, TypeInfo info) {
processObjectFactory(info);
resetProperty(oldProperty, info);
List<XmlElementRef> eltRefs = new ArrayList<XmlElementRef>();
boolean required = true;
for (XmlElementRef eltRef : xmlElementRefs.getXmlElementRef()) {
eltRefs.add(eltRef);
required = required && eltRef.isRequired();
}
oldProperty.setXmlElementRefs(eltRefs);
oldProperty.setIsReference(true);
oldProperty.setIsRequired(required);
// handle XmlAdapter
if (xmlElementRefs.getXmlJavaTypeAdapter() != null) {
oldProperty.setXmlJavaTypeAdapter(xmlElementRefs.getXmlJavaTypeAdapter());
}
// handle XmlElementWrapper
if (xmlElementRefs.getXmlElementWrapper() != null) {
oldProperty.setXmlElementWrapper(xmlElementRefs.getXmlElementWrapper());
}
// set user-defined properties
if (xmlElementRefs.getXmlProperties() != null && xmlElementRefs.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlElementRefs.getXmlProperties().getXmlProperty()));
}
if (xmlElementRefs.isSetXmlMixed()) {
oldProperty.setMixedContent(xmlElementRefs.isXmlMixed());
}
// handle get/set methods
if (xmlElementRefs.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlElementRefs.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlElementRefs.getXmlAccessMethods().getSetMethod());
}
// handle read-only
if (xmlElementRefs.isSetReadOnly()) {
oldProperty.setReadOnly(xmlElementRefs.isReadOnly());
}
// handle write-only
if (xmlElementRefs.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlElementRefs.isWriteOnly());
}
return oldProperty;
}
private Property processXmlTransient(XmlTransient xmlTransient, Property oldProperty) {
if (xmlTransient.isXmlLocation()) {
if (!aProcessor.getHelper().getJavaClass(Constants.LOCATOR_CLASS).isAssignableFrom(oldProperty.getType())) {
throw JAXBException.invalidXmlLocation(oldProperty.getPropertyName(), oldProperty.getType().getName());
}
oldProperty.setXmlLocation(true);
}
oldProperty.setTransient(true);
return oldProperty;
}
private Property processXmlValue(XmlValue xmlValue, Property oldProperty, TypeInfo info, JavaType javaType) {
// reset any existing values
resetProperty(oldProperty, info);
oldProperty.setIsXmlValue(true);
oldProperty.setIsXmlValueExtension(true);
info.setXmlValueProperty(oldProperty);
// handle get/set methods
if (xmlValue.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlValue.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlValue.getXmlAccessMethods().getSetMethod());
}
// check for container type
if (!xmlValue.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlValue.getContainerType());
}
// set type
if (!xmlValue.getType().equals(DEFAULT)) {
JavaClass pType = jModelInput.getJavaModel().getClass(xmlValue.getType());
if (aProcessor.getHelper().isCollectionType(oldProperty.getType())) {
oldProperty.setGenericType(pType);
} else {
oldProperty.setType(pType);
}
oldProperty.setHasXmlElementType(true);
// may need to generate a type info for the type
if (aProcessor.shouldGenerateTypeInfo(pType) && aProcessor.getTypeInfos().get(pType.getQualifiedName()) == null) {
aProcessor.buildNewTypeInfo(new JavaClass[] { pType });
}
}
reapplyPackageAndClassAdapters(oldProperty, info);
// handle XmlJavaTypeAdapter
if (xmlValue.getXmlJavaTypeAdapter() != null) {
try {
oldProperty.setXmlJavaTypeAdapter(xmlValue.getXmlJavaTypeAdapter());
} catch(JAXBException e) {
throw JAXBException.invalidPropertyAdapterClass(xmlValue.getXmlJavaTypeAdapter().getValue(), xmlValue.getJavaAttribute(), javaType.getName());
}
}
// handle read-only
if (xmlValue.isSetReadOnly()) {
oldProperty.setReadOnly(xmlValue.isReadOnly());
}
// handle write-only
if (xmlValue.isSetWriteOnly()) {
oldProperty.setWriteOnly(xmlValue.isWriteOnly());
}
// handle cdata
if (xmlValue.isSetCdata()) {
oldProperty.setCdata(xmlValue.isCdata());
}
// handle null policy
if (xmlValue.getXmlAbstractNullPolicy() != null) {
JAXBElement<? extends XmlAbstractNullPolicy> jaxbElt = xmlValue.getXmlAbstractNullPolicy();
oldProperty.setNullPolicy(jaxbElt.getValue());
}
// set user-defined properties
if (xmlValue.getXmlProperties() != null && xmlValue.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlValue.getXmlProperties().getXmlProperty()));
}
return oldProperty;
}
/**
* Process an XmlSchema. This involves creating a NamespaceInfo instance and
* populating it based on the given XmlSchema.
*
* @see NamespaceInfo
* @see AnnotationsProcessor
* @return newly created namespace info, or null if schema is null
*/
private NamespaceInfo processXmlSchema(XmlBindings xmlBindings, String packageName) {
XmlSchema schema = xmlBindings.getXmlSchema();
if (schema == null) {
return null;
}
// create NamespaceInfo
NamespaceInfo nsInfo = this.aProcessor.findInfoForNamespace(schema.getNamespace());
if(nsInfo == null) {
nsInfo = new NamespaceInfo();
}
// process XmlSchema
XmlNsForm form = schema.getAttributeFormDefault();
nsInfo.setAttributeFormQualified(form.equals(XmlNsForm.QUALIFIED));
form = schema.getElementFormDefault();
nsInfo.setElementFormQualified(form.equals(XmlNsForm.QUALIFIED));
if (!nsInfo.isElementFormQualified() || nsInfo.isAttributeFormQualified()) {
aProcessor.setDefaultNamespaceAllowed(false);
}
// make sure defaults are set, not null
nsInfo.setLocation(schema.getLocation() == null ? GENERATE : schema.getLocation());
String namespace = schema.getNamespace();
if(namespace == null) {
namespace = this.aProcessor.getDefaultTargetNamespace();
}
nsInfo.setNamespace(namespace == null ? "" : schema.getNamespace());
NamespaceResolver nsr = new NamespaceResolver();
// process XmlNs
for (XmlNs xmlns : schema.getXmlNs()) {
nsr.put(xmlns.getPrefix(), xmlns.getNamespaceUri());
}
nsInfo.setNamespaceResolver(nsr);
return nsInfo;
}
/**
* Process an XmlTransformation. The info in the XmlTransformation will be
* used to generate an XmlTransformationMapping in MappingsGenerator.
*
*/
private Property processXmlTransformation(XmlTransformation xmlTransformation, Property oldProperty, TypeInfo tInfo) {
// reset any existing values
resetProperty(oldProperty, tInfo);
oldProperty.setIsXmlTransformation(true);
oldProperty.setXmlTransformation(xmlTransformation);
// handle get/set methods
if (xmlTransformation.getXmlAccessMethods() != null) {
oldProperty.setMethodProperty(true);
oldProperty.setGetMethodName(xmlTransformation.getXmlAccessMethods().getGetMethod());
oldProperty.setSetMethodName(xmlTransformation.getXmlAccessMethods().getSetMethod());
}
// set user-defined properties
if (xmlTransformation.getXmlProperties() != null && xmlTransformation.getXmlProperties().getXmlProperty().size() > 0) {
oldProperty.setUserProperties(createUserPropertyMap(xmlTransformation.getXmlProperties().getXmlProperty()));
}
aProcessor.getReferencedByTransformer().add(oldProperty.getType().getName());
return oldProperty;
}
/**
* Process XmlJoinNodes. This method sets the XmlJoinNodes instance on the Property
* for use in MappingsGen and SchemaGen.
*
*/
private Property processXmlJoinNodes(XmlJoinNodes xmlJoinNodes, Property oldProperty, TypeInfo typeInfo) {
// reset any existing values
resetProperty(oldProperty, typeInfo);
oldProperty.setXmlJoinNodes(xmlJoinNodes);
// check for container type
if (!xmlJoinNodes.getContainerType().equals(DEFAULT)) {
setContainerType(oldProperty, xmlJoinNodes.getContainerType());
}
// set type
if (!xmlJoinNodes.getType().equals(DEFAULT)) {
JavaClass pType = jModelInput.getJavaModel().getClass(xmlJoinNodes.getType());
if (aProcessor.getHelper().isCollectionType(oldProperty.getType())) {
oldProperty.setGenericType(pType);
} else {
oldProperty.setType(pType);
}
oldProperty.setHasXmlElementType(true);
// may need to generate a type info for the type
if (aProcessor.shouldGenerateTypeInfo(pType) && aProcessor.getTypeInfos().get(pType.getQualifiedName()) == null) {
aProcessor.buildNewTypeInfo(new JavaClass[] { pType });
}
}
return oldProperty;
}
/**
* Convenience method for building a Map of package to classes.
*
*/
private Map<String, ArrayList<JavaClass>> buildPackageToJavaClassMap() {
Map<String, ArrayList<JavaClass>> theMap = new HashMap<String, ArrayList<JavaClass>>();
Map<String, ArrayList<JavaClass>> xmlBindingsMap = new HashMap<String, ArrayList<JavaClass>>();
XmlBindings xmlBindings;
for (String packageName : xmlBindingMap.keySet()) {
xmlBindings = xmlBindingMap.get(packageName);
ArrayList<JavaClass> classes = new ArrayList<JavaClass>();
// add binding classes - the Java Model will be used to get a
// JavaClass via class name
JavaTypes jTypes = xmlBindings.getJavaTypes();
if (jTypes != null) {
for (JavaType javaType : jTypes.getJavaType()) {
addClassToList(classes, javaType.getName(), packageName);
}
}
// add any enum types to the class list
XmlEnums xmlEnums = xmlBindings.getXmlEnums();
if (xmlEnums != null) {
for (XmlEnum xmlEnum : xmlEnums.getXmlEnum()) {
addClassToList(classes, xmlEnum.getJavaEnum(), packageName);
}
}
theMap.put(packageName, classes);
xmlBindingsMap.put(packageName, new ArrayList(classes));
}
// add any other classes that aren't declared via external metadata
for (JavaClass jClass : jModelInput.getJavaClasses()) {
// need to verify that the class isn't already in the bindings file
// list
String pkg = jClass.getPackageName();
ArrayList<JavaClass> existingXmlBindingsClasses = xmlBindingsMap.get(pkg);
ArrayList<JavaClass> allExistingClasses = theMap.get(pkg);
if (existingXmlBindingsClasses != null) {
if (!classExistsInArray(jClass, existingXmlBindingsClasses)) {
allExistingClasses.add(jClass);
}
} else {
if (allExistingClasses != null) {
allExistingClasses.add(jClass);
} else {
ArrayList<JavaClass> classes = new ArrayList<JavaClass>();
classes.add(jClass);
theMap.put(pkg, classes);
}
}
}
return theMap;
}
private void addClassToList(List classes, String name, String packageName){
JavaClass nextClass = jModelInput.getJavaModel().getClass(getQualifiedJavaTypeName(name, packageName));
String nextPackageName = nextClass.getPackageName();
if(nextPackageName == null || !nextPackageName.equals(packageName)){
throw JAXBException.javaTypeNotAllowedInBindingsFile(nextPackageName, packageName);
}
classes.add(nextClass);
}
/**
* Lazy load the metadata logger.
*
*/
private JAXBMetadataLogger getLogger() {
if (logger == null) {
logger = new JAXBMetadataLogger();
}
return logger;
}
/**
* Convenience method to determine if a class exists in a given ArrayList.
* The classes are compared via equals() method.
*/
public boolean classExistsInArray(JavaClass theClass, ArrayList<JavaClass> existingClasses) {
return aProcessor.getHelper().classExistsInArray(theClass, existingClasses);
}
/**
* Convenience method for resetting a number of properties on a given
* property.
*
*/
private Property resetProperty(Property oldProperty, TypeInfo tInfo) {
oldProperty.setIsAttribute(false);
oldProperty.setHasXmlElementType(false);
oldProperty.setIsRequired(false);
oldProperty.setIsXmlList(false);
oldProperty.setXmlJavaTypeAdapter(null);
oldProperty.setInverseReferencePropertyName(null);
oldProperty.setDefaultValue(null);
oldProperty.setDomHandlerClassName(null);
oldProperty.setIsSwaAttachmentRef(false);
oldProperty.setIsXmlIdRef(false);
oldProperty.setIsXmlTransformation(false);
oldProperty.setXmlElementWrapper(null);
oldProperty.setLax(false);
oldProperty.setNillable(false);
oldProperty.setMixedContent(false);
oldProperty.setMimeType(null);
oldProperty.setTransient(false);
oldProperty.setChoice(false);
oldProperty.setIsReference(false);
oldProperty.setXmlPath(null);
oldProperty.setReadOnly(false);
oldProperty.setWriteOnly(false);
oldProperty.setCdata(false);
oldProperty.setNullPolicy(null);
oldProperty.setUserProperties(null);
oldProperty.setGetMethodName(oldProperty.getOriginalGetMethodName());
oldProperty.setSetMethodName(oldProperty.getOriginalSetMethodName());
oldProperty.setXmlTransformation(null);
oldProperty.setXmlJoinNodes(null);
if (oldProperty.getGetMethodName() == null && oldProperty.getSetMethodName() == null) {
oldProperty.setMethodProperty(false);
}
oldProperty.setIsSwaAttachmentRef(false);
oldProperty.setIsMtomAttachment(false);
oldProperty.setSchemaType(null);
unsetXmlElementRefs(oldProperty, tInfo);
unsetXmlElements(oldProperty);
unsetXmlAnyAttribute(oldProperty, tInfo);
unsetXmlAnyElement(oldProperty, tInfo);
unsetXmlValue(oldProperty, tInfo);
unsetXmlID(oldProperty, tInfo);
unsetXmlKey(oldProperty, tInfo);
return oldProperty;
}
/**
* Ensure that a given property is not set as an xml-id.
*
*/
private void unsetXmlID(Property oldProperty, TypeInfo tInfo) {
oldProperty.setIsXmlId(false);
oldProperty.setIsXmlIdExtension(false);
if (tInfo.isIDSet() && tInfo.getIDProperty().getPropertyName().equals(oldProperty.getPropertyName())) {
tInfo.setIDProperty(null);
}
}
/**
* Ensure that a given property is not set as an xml-key.
*
*/
private void unsetXmlKey(Property oldProperty, TypeInfo tInfo) {
if (tInfo.hasXmlKeyProperties()) {
Property propToRemove = null;
for (Property prop : tInfo.getXmlKeyProperties()) {
if (prop.getPropertyName().equals(oldProperty.getPropertyName())) {
propToRemove = prop;
}
}
if (propToRemove != null) {
tInfo.getXmlKeyProperties().remove(propToRemove);
}
}
}
/**
* Ensure that a given property is not set as an xml-element-refs.
*
*/
private void unsetXmlElementRefs(Property oldProperty, TypeInfo tInfo) {
if (tInfo.hasElementRefs() && tInfo.getElementRefsPropName().equals(oldProperty.getPropertyName())) {
tInfo.setElementRefsPropertyName(null);
}
}
/**
* Ensure that a given property is not set as an xml-elements.
*
*/
private void unsetXmlElements(Property oldProperty) {
oldProperty.setXmlElements(null);
oldProperty.setChoiceProperties(null);
}
/**
* Ensure that a given property is not set as an xml-any-attribute.
*
*/
private void unsetXmlAnyAttribute(Property oldProperty, TypeInfo tInfo) {
oldProperty.setIsAnyAttribute(false);
if (tInfo.isSetAnyAttributePropertyName() && tInfo.getAnyAttributePropertyName().equals(oldProperty.getPropertyName())) {
tInfo.setAnyAttributePropertyName(null);
}
}
/**
* Ensure that a given property is not set as an xml-any-element.
*
*/
private void unsetXmlAnyElement(Property oldProperty, TypeInfo tInfo) {
oldProperty.setIsAny(false);
if (tInfo.isSetAnyElementPropertyName() && tInfo.getAnyElementPropertyName().equals(oldProperty.getPropertyName())) {
tInfo.setAnyElementPropertyName(null);
}
}
/**
* Ensure that a given property is not set as an xml-value.
*
*/
private void unsetXmlValue(Property oldProperty, TypeInfo tInfo) {
oldProperty.setIsXmlValue(false);
oldProperty.setIsXmlValueExtension(false);
if (tInfo.isSetXmlValueProperty() && tInfo.getXmlValueProperty().getPropertyName().equals(oldProperty.getPropertyName())) {
tInfo.setXmlValueProperty(null);
}
}
/**
* Convenience method that returns the field name for a given xml-path. This method
* would typically be called when building a QName to set as the 'SchemaName' on
* a Property.
*
* Examples:
* - returns 'id' for xml-path '@id'
* - returns 'managerId' for xml-path 'projects/prj:project/@prj:managerId'
* - returns 'first-name' for xml-path 'info/personal-info/first-name/text()'
* - returns 'project' for xml-path 'projects/prj:project/text()'
* - returns 'data' for xml-path 'pieces-of-data/data[1]/text()'
*
*/
public static String getNameFromXPath(String xpath, String propertyName, boolean isAttribute) {
// handle self mapping
if (xpath.equals(SELF)) {
return propertyName;
}
String name;
String path;
// may need to strip off '/text()'
int idx = xpath.indexOf(SLASH + Constants.TEXT);
if (idx >= 0) {
path = xpath.substring(0, idx);
} else {
path = xpath;
}
idx = path.lastIndexOf(SLASH);
if (idx >= 0 && path.length() > 1) {
name = path.substring(idx+1);
// may have a prefix
StringTokenizer stok = new StringTokenizer(name, Character.toString(COLON));
if (stok.countTokens() == 2) {
// first token is prefix
stok.nextToken();
// second token is the field name
name = stok.nextToken();
}
} else {
name = path;
}
// may need to strip off '@'
if (isAttribute) {
idx = name.indexOf(Constants.ATTRIBUTE);
if (idx >= 0 && name.length() > 1) {
name = name.substring(idx+1);
}
} else {
// may need to strip of positional info
idx = name.indexOf(OPEN_BRACKET);
if (idx != -1) {
name = name.substring(0, idx);
}
}
return name;
}
private void processObjectFactory(TypeInfo tInfo){
int index = tInfo.getJavaClassName().lastIndexOf('.');
if(index > -1){
String objectFactoryClassName = tInfo.getJavaClassName().substring(0, index) + ".ObjectFactory";
aProcessor.findAndProcessObjectFactory(objectFactoryClassName);
}else{
aProcessor.findAndProcessObjectFactory("ObjectFactory");
}
}
/**
* Return a Map of user-defined properties. Typically the key will
* be a String (property name) and the value a String or some
* other simple type that was converted by ConversionManager,
* i.e. numerical, boolean, temporal.
*
*/
private Map createUserPropertyMap(List<XmlProperty> propList) {
return mergeUserPropertyMap(propList, new HashMap());
}
/**
* Return a Map of user-defined properties. The List of properties (from
* xml) will be merged with the given Map (from annotations). In the
* case of a conflict, xml will win.
*
* Note that this intended to be used when processing type-level user
* properties, as at the property-level, xml completely replaces any
* properties set via annotation.
*
* Typically the key will be a String (property name) and the value a
* String or some other simple type that was converted by
* ConversionManager, i.e. numerical, boolean, temporal.
*
*/
private Map mergeUserPropertyMap(List<XmlProperty> propList, Map existingMap) {
Map propMap = existingMap;
for (XmlProperty prop : propList) {
Object pvalue = prop.getValue();
if (prop.isSetValueType()) {
pvalue = XMLConversionManager.getDefaultXMLManager().convertObject(
prop.getValue(), XMLConversionManager.getDefaultXMLManager().convertClassNameToClass(prop.getValueType()));
}
propMap.put(prop.getName(), pvalue);
}
return propMap;
}
/**
* Convenience method for setting the container class on a given property.
* The generic type will be overwritten, and could be incorrect after
* doing so, so the original generic type will be retrieved and set after
* the call to set the container type.
*
*/
private void setContainerType(Property property, String containerClassName) {
// store the original generic type as the call to setType will overwrite it
JavaClass genericType = property.getGenericType();
// set the type to the container-type value
property.setType(jModelInput.getJavaModel().getClass(containerClassName));
// set the original generic type
property.setGenericType(genericType);
}
/**
* This method checks for class and package level adapters after the type of a property has been set.
* @param prop the property that needs to be updated
* @param owningInfo the typeInfo that represents the owner of this property.
*/
public void reapplyPackageAndClassAdapters(Property prop, TypeInfo owningInfo) {
if(prop.getXmlJavaTypeAdapter() != null) {
//if there's already a property level adapter, don't apply package/class level
return;
}
JavaClass type = prop.getActualType();
//if a class level adapter is present on the target class, set it
TypeInfo targetInfo = aProcessor.getTypeInfos().get(type.getQualifiedName());
if(targetInfo != null) {
if(targetInfo.getXmlJavaTypeAdapter() != null) {
prop.setXmlJavaTypeAdapter(targetInfo.getXmlJavaTypeAdapter());
}
}
//check for package level adapter. Don't overwrite class level
if(owningInfo.hasPackageLevelAdaptersByClass()) {
JavaClass packageLevelAdapter = owningInfo.getPackageLevelAdaptersByClass().get(type.getQualifiedName());
if(packageLevelAdapter != null && prop.getXmlJavaTypeAdapter() == null) {
org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xja = new org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter();
xja.setValue(packageLevelAdapter.getQualifiedName());
xja.setType(type.getQualifiedName());
prop.setXmlJavaTypeAdapter(xja);
}
}
}
/**
* This method is used to merge several bindings files into one XMLBindings object.
* @param bindings the list of XmlBindings objects to merge.
* @return XmlBindings object representing the merged files.
*/
public static XmlBindings mergeXmlBindings(List<XmlBindings> bindings) {
if(bindings.size() == 0) {
return null;
}
XmlBindings rootBindings = bindings.get(0);
for(int i = 1; i < bindings.size(); i++) {
XmlBindings nextBindings = bindings.get(i);
if(nextBindings.isSetXmlAccessorOrder()) {
rootBindings.setXmlAccessorOrder(nextBindings.getXmlAccessorOrder());
}
if(nextBindings.isSetXmlAccessorType()) {
rootBindings.setXmlAccessorType(nextBindings.getXmlAccessorType());
}
if(nextBindings.isSetXmlMappingMetadataComplete()) {
rootBindings.setXmlMappingMetadataComplete(nextBindings.isXmlMappingMetadataComplete());
}
mergeJavaTypes(rootBindings.getJavaTypes(), nextBindings.getJavaTypes());
if(rootBindings.getXmlEnums() == null) {
rootBindings.setXmlEnums(nextBindings.getXmlEnums());
} else {
mergeXmlEnums(rootBindings.getXmlEnums(), nextBindings.getXmlEnums());
}
if(rootBindings.getXmlSchema() == null) {
rootBindings.setXmlSchema(nextBindings.getXmlSchema());
} else if(nextBindings.getXmlSchema() != null){
mergeXmlSchema(rootBindings.getXmlSchema(), nextBindings.getXmlSchema());
}
if(rootBindings.getXmlSchemaType() == null) {
rootBindings.setXmlSchemaTypes(nextBindings.getXmlSchemaTypes());
} else if(nextBindings.getXmlSchemaTypes() != null){
mergeXmlSchemaTypes(rootBindings.getXmlSchemaTypes(), nextBindings.getXmlSchemaTypes());
}
if(rootBindings.getXmlJavaTypeAdapters() == null) {
rootBindings.setXmlJavaTypeAdapters(nextBindings.getXmlJavaTypeAdapters());
} else if(nextBindings.getXmlJavaTypeAdapters() != null){
mergeXmlJavaTypeAdapters(rootBindings.getXmlJavaTypeAdapters(), nextBindings.getXmlJavaTypeAdapters());
}
if (rootBindings.getXmlNullPolicy() == null) {
rootBindings.setXmlNullPolicy(nextBindings.getXmlNullPolicy());
} else if (nextBindings.getXmlNullPolicy() != null) {
mergeXmlNullPolicy(rootBindings.getXmlNullPolicy(), nextBindings.getXmlNullPolicy());
}
if (rootBindings.getXmlElementNillable() == null) {
rootBindings.setXmlElementNillable(nextBindings.getXmlElementNillable());
} else if (nextBindings.getXmlElementNillable() != null) {
mergeXmlElementNillable(rootBindings.getXmlElementNillable(), nextBindings.getXmlElementNillable());
}
}
return rootBindings;
}
private static void mergeXmlElementNillable(XmlElementNillable xmlElementNillable, XmlElementNillable overrideXmlElementNillable) {
xmlElementNillable.setNillable(overrideXmlElementNillable.isNillable());
}
private static void mergeXmlNullPolicy(XmlNullPolicy xmlNullPolicy, XmlNullPolicy overrideXmlNullPolicy) {
xmlNullPolicy.setEmptyNodeRepresentsNull(overrideXmlNullPolicy.isEmptyNodeRepresentsNull());
xmlNullPolicy.setIsSetPerformedForAbsentNode(overrideXmlNullPolicy.isIsSetPerformedForAbsentNode());
xmlNullPolicy.setNullRepresentationForXml(overrideXmlNullPolicy.getNullRepresentationForXml());
xmlNullPolicy.setXsiNilRepresentsNull(overrideXmlNullPolicy.isXsiNilRepresentsNull());
}
private static void mergeXmlJavaTypeAdapters(XmlJavaTypeAdapters xmlJavaTypeAdapters, XmlJavaTypeAdapters overrideAdapters) {
List<XmlJavaTypeAdapter> adapterList = xmlJavaTypeAdapters.getXmlJavaTypeAdapter();
HashMap<String, XmlJavaTypeAdapter> adapterMap = new HashMap<String, XmlJavaTypeAdapter>(adapterList.size());
for(XmlJavaTypeAdapter next:adapterList) {
adapterMap.put(next.getType(), next);
}
for(XmlJavaTypeAdapter next:overrideAdapters.getXmlJavaTypeAdapter()) {
//If there's already an adapter for this type, replace it's value
XmlJavaTypeAdapter existingAdapter = adapterMap.get(next.getType());
if(existingAdapter != null) {
existingAdapter.setValue(next.getValue());
} else {
xmlJavaTypeAdapters.getXmlJavaTypeAdapter().add(next);
}
}
}
private static void mergeXmlSchemaTypes(XmlSchemaTypes xmlSchemaTypes, XmlSchemaTypes overrideSchemaTypes) {
List<XmlSchemaType> schemaTypeList = xmlSchemaTypes.getXmlSchemaType();
HashMap<String, XmlSchemaType> schemaTypeMap = new HashMap<String, XmlSchemaType>(schemaTypeList.size());
for(XmlSchemaType next:schemaTypeList) {
schemaTypeMap.put(next.getType(), next);
}
for(XmlSchemaType next:overrideSchemaTypes.getXmlSchemaType()) {
//if there's already a schemaType for this type, override it's value
XmlSchemaType existingType = schemaTypeMap.get(next.getType());
if(existingType != null) {
existingType.setName(next.getName());
existingType.setNamespace(next.getNamespace());
} else {
xmlSchemaTypes.getXmlSchemaType().add(next);
}
}
}
private static void mergeXmlSchema(XmlSchema xmlSchema, XmlSchema overrideSchema) {
xmlSchema.setAttributeFormDefault(overrideSchema.getAttributeFormDefault());
xmlSchema.setElementFormDefault(overrideSchema.getElementFormDefault());
xmlSchema.setLocation(overrideSchema.getLocation());
xmlSchema.setNamespace(overrideSchema.getNamespace());
List<XmlNs> xmlNsList = xmlSchema.getXmlNs();
xmlNsList.addAll(overrideSchema.getXmlNs());
}
private static void mergeXmlEnums(XmlEnums xmlEnums, XmlEnums overrideEnum) {
if(overrideEnum == null) {
return;
}
List<XmlEnum> enumList = xmlEnums.getXmlEnum();
Map<String, XmlEnum> enumMap = new HashMap<String, XmlEnum>(enumList.size());
for(XmlEnum next:enumList) {
enumMap.put(next.getJavaEnum(), next);
}
for(XmlEnum next:overrideEnum.getXmlEnum()) {
XmlEnum existingEnum = enumMap.get(next.getJavaEnum());
if(existingEnum != null) {
mergeXmlEnumValues(existingEnum.getXmlEnumValue(), next.getXmlEnumValue());
} else {
xmlEnums.getXmlEnum().add(next);
}
}
}
private static void mergeXmlEnumValues(List<XmlEnumValue> xmlEnumValue, List<XmlEnumValue> overrideXmlEnumValue) {
Map<String, XmlEnumValue> values = new HashMap<String, XmlEnumValue>();
List<XmlEnumValue> extraValues = new ArrayList<XmlEnumValue>();
for(XmlEnumValue next:xmlEnumValue){
values.put(next.getJavaEnumValue(), next);
}
for(XmlEnumValue next:overrideXmlEnumValue) {
XmlEnumValue existingValue = values.get(next.getJavaEnumValue());
if(existingValue == null) {
extraValues.add(next);
} else {
existingValue.setValue(next.getValue());
}
}
xmlEnumValue.addAll(extraValues);
}
private static void mergeJavaTypes(JavaTypes javaTypes, JavaTypes overrideJavaTypes) {
List<JavaType> javaTypeList = javaTypes.getJavaType();
Map<String, JavaType> javaTypeMap = new HashMap<String, JavaType>(javaTypeList.size());
for(JavaType next:javaTypeList) {
javaTypeMap.put(next.getName(), next);
}
for(JavaType next:overrideJavaTypes.getJavaType()) {
JavaType existingType = javaTypeMap.get(next.getName());
if(existingType == null) {
javaTypes.getJavaType().add(next);
} else {
mergeJavaType(existingType, next);
}
}
}
private static void mergeJavaType(JavaType existingType, JavaType next) {
if(next.isSetXmlAccessorOrder()) {
existingType.setXmlAccessorOrder(next.getXmlAccessorOrder());
}
if(next.isSetXmlAccessorType()) {
existingType.setXmlAccessorType(next.getXmlAccessorType());
}
if(next.isSetXmlInlineBinaryData()) {
existingType.setXmlInlineBinaryData(next.isXmlInlineBinaryData());
}
if(next.isSetXmlTransient()) {
existingType.setXmlTransient(next.isXmlInlineBinaryData());
}
if(next.getXmlRootElement() != null) {
existingType.setXmlRootElement(next.getXmlRootElement());
}
if(existingType.getXmlProperties() == null) {
existingType.setXmlProperties(next.getXmlProperties());
} else if(next.getXmlProperties() != null) {
existingType.getXmlProperties().getXmlProperty().addAll(next.getXmlProperties().getXmlProperty());
}
if(next.getXmlType() != null) {
existingType.setXmlType(next.getXmlType());
}
existingType.getXmlSeeAlso().addAll(next.getXmlSeeAlso());
JavaAttributes attributes = existingType.getJavaAttributes();
JavaAttributes overrideAttributes = next.getJavaAttributes();
if(attributes == null) {
existingType.setJavaAttributes(overrideAttributes);
} else if(overrideAttributes != null) {
mergeJavaAttributes(attributes, overrideAttributes, existingType);
}
}
private static void mergeJavaAttributes(JavaAttributes attributes, JavaAttributes overrideAttributes, JavaType javaType) {
List<JAXBElement<? extends JavaAttribute>> attributeList = attributes.getJavaAttribute();
Map<String, JAXBElement> attributeMap = new HashMap<String, JAXBElement>(attributeList.size());
for(JAXBElement next:attributeList) {
attributeMap.put(((JavaAttribute)next.getValue()).getJavaAttribute(), next);
}
for(JAXBElement next:overrideAttributes.getJavaAttribute()) {
JAXBElement existingAttribute = attributeMap.get(((JavaAttribute)next.getValue()).getJavaAttribute());
if(existingAttribute != null) {
attributes.getJavaAttribute().remove(existingAttribute);
}
attributes.getJavaAttribute().add(next);
}
}
}