org.eclipse.persistence.jaxb.compiler.XMLProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of eclipselink Show documentation
Show all versions of eclipselink Show documentation
EclipseLink build based upon Git transaction f2b9fc5
/*
* 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:
*
* 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).
*
*
*
* As a general rule meta data provided in external OXM XML files overrides meta data
* specified through annotations.
*
* @see org.eclipse.persistence.jaxb.compiler.Generator
*/
public class XMLProcessor {
private Map 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.
*
* @param bindings
*/
public XMLProcessor(Map bindings) {
this.xmlBindingMap = bindings;
}
/**
* Process XmlBindings on a per package basis for a given
* AnnotationsProcessor instance.
*
* @param annotationsProcessor
*/
public void processXML(AnnotationsProcessor annotationsProcessor, JavaModelInput jModelInput, TypeMappingInfo[] typeMappingInfos, JavaClass[] originalJavaClasses) {
this.jModelInput = jModelInput;
this.aProcessor = annotationsProcessor;
this.aProcessor.setHasXmlBindings(true);
Map xmlEnumMap = new HashMap();
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> pkgToClassMap = buildPackageToJavaClassMap();
// process each XmlBindings in the map
XmlBindings xmlBindings;
for (String packageName : xmlBindingMap.keySet()) {
ArrayList 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 = (JavaClass[]) 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 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 typeInfoMap = aProcessor.preBuildTypeInfo(javaClasses);
// handle package-level xml-schema-types
List xmlSchemaTypes = null;
XmlSchemaTypes sTypes = xmlBindings.getXmlSchemaTypes();
if (sTypes != null) {
xmlSchemaTypes = sTypes.getXmlSchemaType();
} else {
xmlSchemaTypes = new ArrayList();
}
// 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 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 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 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 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 = (JavaClass[]) classesToProcess.toArray(new JavaClass[classesToProcess.size()]);
// post-build the TypeInfo objects
javaClasses = aProcessor.postBuildTypeInfo(javaClasses);
// get the generated TypeInfo
Map typeInfosForPackage = aProcessor.getTypeInfosForPackage(packageName);
// update xml-enum info if necessary
for (Entry 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> classIt = pkgToClassMap.values().iterator();
while (classIt.hasNext()) {
ArrayList 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 typeInfos = (Map) ((HashMap)aProcessor.getTypeInfos()).clone();
for (Entry 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 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.
*
* @param javaType
* @param typeInfo
* @param nsInfo
*/
private void processJavaType(JavaType javaType, TypeInfo typeInfo, NamespaceInfo nsInfo) {
// process field/property overrides
if (null != javaType.getJavaAttributes()) {
List processedPropertyNames = new ArrayList();
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 additionalProps = null;
if(typeInfo.hasAdditionalProperties()) {
additionalProps = typeInfo.getAdditionalProperties().get(javaAttribute.getJavaAttribute());
}
if (additionalProps == null) {
additionalProps = new ArrayList();
}
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.
*
* @param javaAttribute
* @param oldProperty
* @param nsInfo
* @return
*/
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
*
* @param xmlAdapter
* @param oldProperty
* @return
*/
private Property processXmlJavaTypeAdapter(XmlJavaTypeAdapter xmlAdapter, Property oldProperty) {
oldProperty.setXmlJavaTypeAdapter(xmlAdapter);
return oldProperty;
}
/**
* Handle xml-inverse-reference.
*
* @param xmlInverseReference
* @param oldProperty
* @return
*/
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.
*
* @param xmlAnyAttribute
* @param oldProperty
* @param tInfo
* @param javaType
* @return
*/
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.
*
* @param xmlAnyElement
* @param oldProperty
* @param tInfo
* @param javaType
* @return
*/
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.
*
* @param xmlAttribute
* @param oldProperty
* @param nsInfo
* @return
*/
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 jaxbElt = xmlAttribute.getXmlAbstractNullPolicy();
oldProperty.setNullPolicy((XmlAbstractNullPolicy) 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.
*
* @param xmlElement
* @param oldProperty
* @param typeInfo
* @param nsInfo
* @return
*/
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 jaxbElt = xmlElement.getXmlAbstractNullPolicy();
oldProperty.setNullPolicy((XmlAbstractNullPolicy) 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'.
*
* @param xmlElements
* @param oldProperty
* @param tInfo
* @return
*/
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.
*
* @param xmlElementRef
* @param oldProperty
* @param info
* @return
*/
private Property processXmlElementRef(XmlElementRef xmlElementRef, Property oldProperty, TypeInfo info) {
processObjectFactory(info);
resetProperty(oldProperty, info);
List eltRefs = new ArrayList();
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.
*
* @param xmlElementRefs
* @param oldProperty
* @param info
* @return
*/
private Property processXmlElementRefs(XmlElementRefs xmlElementRefs, Property oldProperty, TypeInfo info) {
processObjectFactory(info);
resetProperty(oldProperty, info);
List eltRefs = new ArrayList();
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 jaxbElt = xmlValue.getXmlAbstractNullPolicy();
oldProperty.setNullPolicy((XmlAbstractNullPolicy) 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.
*
* @param xmlBindings
* @param packageName
* @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.
*
* @param xmlTransformation
* @param oldProperty
* @param tInfo
*/
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.
*
* @param xmlJoinNodes
* @param oldProperty
* @return
*/
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.
*
* @return
*/
private Map> buildPackageToJavaClassMap() {
Map> theMap = new HashMap>();
Map> xmlBindingsMap = new HashMap>();
XmlBindings xmlBindings;
for (String packageName : xmlBindingMap.keySet()) {
xmlBindings = xmlBindingMap.get(packageName);
ArrayList classes = new ArrayList();
// 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 existingXmlBindingsClasses = xmlBindingsMap.get(pkg);
ArrayList allExistingClasses = theMap.get(pkg);
if (existingXmlBindingsClasses != null) {
if (!classExistsInArray(jClass, existingXmlBindingsClasses)) {
allExistingClasses.add(jClass);
}
} else {
if (allExistingClasses != null) {
allExistingClasses.add(jClass);
} else {
ArrayList classes = new ArrayList();
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.
*
* @return
*/
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 existingClasses) {
return aProcessor.getHelper().classExistsInArray(theClass, existingClasses);
}
/**
* Convenience method for resetting a number of properties on a given
* property.
*
* @param oldProperty
* @return
*/
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.
*
* @param oldProperty
* @param tInfo
*/
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.
*
* @param oldProperty
* @param tInfo
*/
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.
*
* @param oldProperty
* @param tInfo
*/
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.
*
* @param oldProperty
*/
private void unsetXmlElements(Property oldProperty) {
oldProperty.setXmlElements(null);
oldProperty.setChoiceProperties(null);
}
/**
* Ensure that a given property is not set as an xml-any-attribute.
*
* @param oldProperty
* @param tInfo
*/
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.
*
* @param oldProperty
* @param tInfo
*/
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.
*
* @param oldProperty
* @param tInfo
*/
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()'
*
* @param xpath
* @param propertyName
* @param isAttribute
* @return
*/
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.
*
* @param propList
* @return
*/
private Map createUserPropertyMap(List 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.
*
* @param propList
* @return
*/
private Map mergeUserPropertyMap(List 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.
*
* @param property
* @param containerClassName
*/
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 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 adapterList = xmlJavaTypeAdapters.getXmlJavaTypeAdapter();
HashMap adapterMap = new HashMap(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 schemaTypeList = xmlSchemaTypes.getXmlSchemaType();
HashMap schemaTypeMap = new HashMap(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 xmlNsList = xmlSchema.getXmlNs();
xmlNsList.addAll(overrideSchema.getXmlNs());
}
private static void mergeXmlEnums(XmlEnums xmlEnums, XmlEnums overrideEnum) {
if(overrideEnum == null) {
return;
}
List enumList = xmlEnums.getXmlEnum();
Map enumMap = new HashMap(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, List overrideXmlEnumValue) {
Map values = new HashMap();
List extraValues = new ArrayList();
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 javaTypeList = javaTypes.getJavaType();
Map javaTypeMap = new HashMap(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> attributeList = attributes.getJavaAttribute();
Map attributeMap = new HashMap(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);
}
}
}