/******************************************************************************* | |
* Copyright (c) 1998, 2012 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 v1.0 and Eclipse Distribution License v. 1.0 | |
* which accompanies this distribution. | |
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html | |
* and the Eclipse Distribution License is available at | |
* http://www.eclipse.org/org/documents/edl-v10.php. | |
* | |
* Contributors: | |
* Oracle - initial API and implementation from Oracle TopLink | |
******************************************************************************/ | |
package org.eclipse.persistence.jaxb.compiler; | |
import java.awt.Image; | |
import java.beans.Introspector; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Deque; | |
import java.util.Enumeration; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.NavigableSet; | |
import java.util.Queue; | |
import java.util.Set; | |
import java.util.Map.Entry; | |
import java.util.SortedSet; | |
import java.util.StringTokenizer; | |
import java.util.TreeSet; | |
import javax.xml.bind.JAXBElement; | |
import javax.xml.bind.annotation.XmlAttribute; | |
import javax.xml.bind.annotation.XmlMixed; | |
import javax.xml.bind.annotation.XmlTransient; | |
import javax.xml.bind.annotation.XmlValue; | |
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter; | |
import javax.xml.bind.annotation.adapters.NormalizedStringAdapter; | |
import javax.xml.namespace.QName; | |
import javax.xml.transform.Source; | |
import org.eclipse.persistence.config.DescriptorCustomizer; | |
import org.eclipse.persistence.dynamic.DynamicClassLoader; | |
import org.eclipse.persistence.exceptions.DescriptorException; | |
import org.eclipse.persistence.exceptions.JAXBException; | |
import org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor; | |
import org.eclipse.persistence.internal.descriptors.InstantiationPolicy; | |
import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor; | |
import org.eclipse.persistence.internal.descriptors.VirtualAttributeAccessor; | |
import org.eclipse.persistence.internal.helper.ClassConstants; | |
import org.eclipse.persistence.internal.jaxb.AccessorFactoryWrapper; | |
import org.eclipse.persistence.internal.jaxb.CustomAccessorAttributeAccessor; | |
import org.eclipse.persistence.internal.jaxb.DefaultElementConverter; | |
import org.eclipse.persistence.internal.jaxb.DomHandlerConverter; | |
import org.eclipse.persistence.internal.jaxb.JAXBElementConverter; | |
import org.eclipse.persistence.internal.jaxb.JAXBElementRootConverter; | |
import org.eclipse.persistence.internal.jaxb.JAXBSetMethodAttributeAccessor; | |
import org.eclipse.persistence.internal.jaxb.JaxbClassLoader; | |
import org.eclipse.persistence.internal.jaxb.MultiArgInstantiationPolicy; | |
import org.eclipse.persistence.internal.jaxb.WrappedValue; | |
import org.eclipse.persistence.internal.jaxb.XMLJavaTypeConverter; | |
import org.eclipse.persistence.internal.jaxb.many.JAXBArrayAttributeAccessor; | |
import org.eclipse.persistence.internal.jaxb.many.ManyValue; | |
import org.eclipse.persistence.internal.jaxb.many.MapValue; | |
import org.eclipse.persistence.internal.jaxb.many.MapValueAttributeAccessor; | |
import org.eclipse.persistence.internal.libraries.asm.ClassWriter; | |
import org.eclipse.persistence.internal.libraries.asm.MethodVisitor; | |
import org.eclipse.persistence.internal.libraries.asm.Opcodes; | |
import org.eclipse.persistence.internal.libraries.asm.Type; | |
import org.eclipse.persistence.internal.oxm.XMLContainerMapping; | |
import org.eclipse.persistence.internal.oxm.XMLConversionManager; | |
import org.eclipse.persistence.internal.queries.ContainerPolicy; | |
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; | |
import org.eclipse.persistence.jaxb.JAXBEnumTypeConverter; | |
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.JavaMethod; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlAbstractNullPolicy; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlIsSetNullPolicy; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlNullPolicy; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlReadTransformer; | |
import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlWriteTransformer; | |
import org.eclipse.persistence.mappings.DatabaseMapping; | |
import org.eclipse.persistence.mappings.converters.Converter; | |
import org.eclipse.persistence.oxm.NamespaceResolver; | |
import org.eclipse.persistence.oxm.XMLConstants; | |
import org.eclipse.persistence.oxm.XMLDescriptor; | |
import org.eclipse.persistence.oxm.XMLField; | |
import org.eclipse.persistence.oxm.mappings.FixedMimeTypePolicy; | |
import org.eclipse.persistence.oxm.mappings.UnmarshalKeepAsElementPolicy; | |
import org.eclipse.persistence.oxm.mappings.XMLAnyAttributeMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLAnyCollectionMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLAnyObjectMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLBinaryDataCollectionMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLBinaryDataMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLChoiceCollectionMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLChoiceObjectMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLCollectionReferenceMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLCompositeObjectMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLDirectMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLInverseReferenceMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping; | |
import org.eclipse.persistence.oxm.mappings.XMLTransformationMapping; | |
import org.eclipse.persistence.oxm.mappings.converters.XMLListConverter; | |
import org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy; | |
import org.eclipse.persistence.oxm.mappings.nullpolicy.IsSetNullPolicy; | |
import org.eclipse.persistence.oxm.mappings.nullpolicy.NullPolicy; | |
import org.eclipse.persistence.oxm.mappings.nullpolicy.XMLNullRepresentationType; | |
import org.eclipse.persistence.oxm.schema.XMLSchemaClassPathReference; | |
import org.eclipse.persistence.oxm.schema.XMLSchemaReference; | |
import org.eclipse.persistence.sessions.Project; | |
/** | |
* INTERNAL: | |
* <p><b>Purpose:</b>To generate a TopLink OXM Project based on Java Class and TypeInfo information | |
* <p><b>Responsibilities:</b><ul> | |
* <li>Generate a XMLDescriptor for each TypeInfo object</li> | |
* <li>Generate a mapping for each TypeProperty object</li> | |
* <li>Determine the correct mapping type based on the type of each property</li> | |
* <li>Set up Converters on mappings for XmlAdapters or JDK 1.5 Enumeration types.</li> | |
* </ul> | |
* <p>This class is invoked by a Generator in order to create a TopLink Project. | |
* This is generally used by JAXBContextFactory to create the runtime project. A Descriptor will | |
* be generated for each TypeInfo and Mappings generated for each Property. In the case that a | |
* non-transient property's type is a user defined class, a Descriptor and Mappings will be generated | |
* for that class as well. | |
* @see org.eclipse.persistence.jaxb.compiler.Generator | |
* @see org.eclipse.persistence.jaxb.compiler.TypeInfo | |
* @see org.eclipse.persistence.jaxb.compiler.Property | |
* @author mmacivor | |
* @since Oracle TopLink 11.1.1.0.0 | |
* | |
*/ | |
public class MappingsGenerator { | |
private static final String ATT = "@"; | |
private static final String TXT = "/text()"; | |
private static String OBJECT_CLASS_NAME = "java.lang.Object"; | |
public static final QName RESERVED_QNAME = new QName("urn:ECLIPSELINK_RESERVEDURI", "RESERVEDNAME"); | |
String outputDir = "."; | |
private HashMap<String, QName> userDefinedSchemaTypes; | |
private Helper helper; | |
private JavaClass jotArrayList; | |
private JavaClass jotHashSet; | |
private JavaClass jotHashMap; | |
private JavaClass jotLinkedList; | |
private JavaClass jotTreeSet; | |
private HashMap<String, PackageInfo> packageToPackageInfoMappings; | |
private HashMap<String, TypeInfo> typeInfo; | |
private HashMap<QName, Class> qNamesToGeneratedClasses; | |
private HashMap<String, Class> classToGeneratedClasses; | |
private HashMap<QName, Class> qNamesToDeclaredClasses; | |
private HashMap<QName, ElementDeclaration> globalElements; | |
private List<ElementDeclaration> localElements; | |
private Map<TypeMappingInfo, Class> typeMappingInfoToGeneratedClasses; | |
private Map<MapEntryGeneratedKey, Class> generatedMapEntryClasses; | |
private Project project; | |
private NamespaceResolver globalNamespaceResolver; | |
private boolean isDefaultNamespaceAllowed; | |
private Map<TypeMappingInfo, Class>typeMappingInfoToAdapterClasses; | |
public MappingsGenerator(Helper helper) { | |
this.helper = helper; | |
jotArrayList = helper.getJavaClass(ArrayList.class); | |
jotHashSet = helper.getJavaClass(HashSet.class); | |
jotHashMap = helper.getJavaClass(HashMap.class); | |
jotLinkedList = helper.getJavaClass(LinkedList.class); | |
jotTreeSet = helper.getJavaClass(TreeSet.class); | |
qNamesToGeneratedClasses = new HashMap<QName, Class>(); | |
qNamesToDeclaredClasses = new HashMap<QName, Class>(); | |
classToGeneratedClasses = new HashMap<String, Class>(); | |
globalNamespaceResolver = new NamespaceResolver(); | |
isDefaultNamespaceAllowed = true; | |
} | |
public Project generateProject(ArrayList<JavaClass> typeInfoClasses, HashMap<String, TypeInfo> typeInfo, HashMap<String, QName> userDefinedSchemaTypes, HashMap<String, PackageInfo> packageToPackageInfoMappings, HashMap<QName, ElementDeclaration> globalElements, List<ElementDeclaration> localElements, Map<TypeMappingInfo, Class> typeMappingInfoToGeneratedClass, Map<TypeMappingInfo, Class> typeMappingInfoToAdapterClasses, boolean isDefaultNamespaceAllowed) throws Exception { | |
this.typeInfo = typeInfo; | |
this.userDefinedSchemaTypes = userDefinedSchemaTypes; | |
this.packageToPackageInfoMappings = packageToPackageInfoMappings; | |
this.isDefaultNamespaceAllowed = isDefaultNamespaceAllowed; | |
this.globalElements = globalElements; | |
this.localElements = localElements; | |
this.typeMappingInfoToGeneratedClasses = typeMappingInfoToGeneratedClass; | |
this.typeMappingInfoToAdapterClasses = typeMappingInfoToAdapterClasses; | |
project = new Project(); | |
// Generate descriptors | |
for (JavaClass next : typeInfoClasses) { | |
if (!next.isEnum()) { | |
generateDescriptor(next, project); | |
} | |
} | |
// Setup inheritance | |
for (JavaClass next : typeInfoClasses) { | |
if (!next.isEnum()) { | |
setupInheritance(next); | |
} | |
} | |
// Now create mappings | |
generateMappings(); | |
// apply customizers if necessary | |
Set<Entry<String, TypeInfo>> entrySet = this.typeInfo.entrySet(); | |
for (Entry<String, TypeInfo> entry : entrySet) { | |
TypeInfo tInfo = entry.getValue(); | |
if (tInfo.getXmlCustomizer() != null) { | |
String customizerClassName = tInfo.getXmlCustomizer(); | |
try { | |
Class customizerClass = PrivilegedAccessHelper.getClassForName(customizerClassName, true, helper.getClassLoader()); | |
DescriptorCustomizer descriptorCustomizer = (DescriptorCustomizer) PrivilegedAccessHelper.newInstanceFromClass(customizerClass); | |
descriptorCustomizer.customize(tInfo.getDescriptor()); | |
} catch (IllegalAccessException iae) { | |
throw JAXBException.couldNotCreateCustomizerInstance(iae, customizerClassName); | |
} catch (InstantiationException ie) { | |
throw JAXBException.couldNotCreateCustomizerInstance(ie, customizerClassName); | |
} catch (ClassCastException cce) { | |
throw JAXBException.invalidCustomizerClass(cce, customizerClassName); | |
} catch (ClassNotFoundException cnfe) { | |
throw JAXBException.couldNotCreateCustomizerInstance(cnfe, customizerClassName); | |
} | |
} | |
} | |
processGlobalElements(project); | |
return project; | |
} | |
public void generateDescriptor(JavaClass javaClass, Project project) { | |
String jClassName = javaClass.getQualifiedName(); | |
TypeInfo info = typeInfo.get(jClassName); | |
if (info.isTransient()){ | |
return; | |
} | |
NamespaceInfo namespaceInfo = this.packageToPackageInfoMappings.get(javaClass.getPackageName()).getNamespaceInfo(); | |
String packageNamespace = namespaceInfo.getNamespace(); | |
String elementName; | |
String namespace; | |
if (javaClass.getSuperclass() != null && javaClass.getSuperclass().getName().equals("javax.xml.bind.JAXBElement")) { | |
generateDescriptorForJAXBElementSubclass(javaClass, project, namespaceInfo.getNamespaceResolverForDescriptor()); | |
return; | |
} | |
XMLDescriptor descriptor = new XMLDescriptor(); | |
org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement rootElem = info.getXmlRootElement(); | |
if (rootElem == null) { | |
try{ | |
elementName = info.getXmlNameTransformer().transformRootElementName(javaClass.getName()); | |
}catch (Exception ex){ | |
throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex); | |
} | |
namespace = packageNamespace; | |
descriptor.setResultAlwaysXMLRoot(true); | |
} else { | |
elementName = rootElem.getName(); | |
if (elementName.equals(XMLProcessor.DEFAULT)) { | |
try{ | |
elementName = info.getXmlNameTransformer().transformRootElementName(javaClass.getName()); | |
}catch (Exception ex){ | |
throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex); | |
} | |
} | |
namespace = rootElem.getNamespace(); | |
descriptor.setResultAlwaysXMLRoot(false); | |
} | |
descriptor.setJavaClassName(jClassName); | |
if (info.getFactoryMethodName() != null) { | |
descriptor.getInstantiationPolicy().useFactoryInstantiationPolicy(info.getObjectFactoryClassName(), info.getFactoryMethodName()); | |
} | |
if (namespace.equals(XMLProcessor.DEFAULT)) { | |
namespace = namespaceInfo.getNamespace(); | |
} | |
JavaClass manyValueJavaClass = helper.getJavaClass(ManyValue.class); | |
if (!manyValueJavaClass.isAssignableFrom(javaClass)){ | |
if(namespace.length() != 0) { | |
if(isDefaultNamespaceAllowed && globalNamespaceResolver.getDefaultNamespaceURI() == null && namespace.length() != 0) { | |
if (!namespaceInfo.getNamespaceResolverForDescriptor().getPrefixesToNamespaces().containsValue(namespace)) { | |
globalNamespaceResolver.setDefaultNamespaceURI(namespace); | |
namespaceInfo.getNamespaceResolverForDescriptor().setDefaultNamespaceURI(namespace); | |
} | |
} | |
} | |
if (rootElem == null) { | |
descriptor.setDefaultRootElement(""); | |
} else { | |
if (namespace.length() == 0) { | |
descriptor.setDefaultRootElement(elementName); | |
} else { | |
descriptor.setDefaultRootElement(getQualifiedString(getPrefixForNamespace(namespace, namespaceInfo.getNamespaceResolverForDescriptor(), null), elementName)); | |
} | |
} | |
} | |
descriptor.setNamespaceResolver(namespaceInfo.getNamespaceResolverForDescriptor()); | |
setSchemaContext(descriptor, info); | |
// set the ClassExtractor class name if necessary | |
if (info.isSetClassExtractorName()) { | |
descriptor.getInheritancePolicy().setClassExtractorName(info.getClassExtractorName()); | |
} | |
// set any user-defined properties | |
if (info.getUserProperties() != null) { | |
descriptor.setProperties(info.getUserProperties()); | |
} | |
if (info.isLocationAware()) { | |
Property locProp = null; | |
Iterator<Property> i = info.getPropertyList().iterator(); | |
while (i.hasNext()) { | |
Property p = i.next(); | |
if (p.getType().getName().equals(XMLConstants.LOCATOR_CLASS_NAME)) { | |
locProp = p; | |
} | |
} | |
if (locProp != null && locProp.isTransient()) { | |
// build accessor | |
// don't make a mapping | |
if (locProp.isMethodProperty()) { | |
MethodAttributeAccessor aa = new MethodAttributeAccessor(); | |
aa.setAttributeName(locProp.getPropertyName()); | |
aa.setSetMethodName(locProp.getSetMethodName()); | |
aa.setGetMethodName(locProp.getGetMethodName()); | |
descriptor.setLocationAccessor(aa); | |
} else { | |
// instance variable property | |
InstanceVariableAttributeAccessor aa = new InstanceVariableAttributeAccessor(); | |
aa.setAttributeName(locProp.getPropertyName()); | |
descriptor.setLocationAccessor(aa); | |
} | |
} | |
} | |
project.addDescriptor(descriptor); | |
info.setDescriptor(descriptor); | |
} | |
public void generateDescriptorForJAXBElementSubclass(JavaClass javaClass, Project project, NamespaceResolver nsr) { | |
String jClassName = javaClass.getQualifiedName(); | |
TypeInfo info = typeInfo.get(jClassName); | |
XMLDescriptor xmlDescriptor = new XMLDescriptor(); | |
xmlDescriptor.setJavaClassName(jClassName); | |
String[] factoryMethodParamTypes = info.getFactoryMethodParamTypes(); | |
MultiArgInstantiationPolicy policy = new MultiArgInstantiationPolicy(); | |
policy.useFactoryInstantiationPolicy(info.getObjectFactoryClassName(), info.getFactoryMethodName()); | |
policy.setParameterTypeNames(factoryMethodParamTypes); | |
policy.setDefaultValues(new String[]{null}); | |
xmlDescriptor.setInstantiationPolicy(policy); | |
JavaClass paramClass = helper.getJavaClass(factoryMethodParamTypes[0]); | |
if(helper.isBuiltInJavaType(paramClass)){ | |
if(isBinaryData(paramClass)){ | |
XMLBinaryDataMapping mapping = new XMLBinaryDataMapping(); | |
mapping.setAttributeName("value"); | |
mapping.setXPath("."); | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
mapping.setSetMethodName("setValue"); | |
mapping.setGetMethodName("getValue"); | |
Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(factoryMethodParamTypes[0], getClass().getClassLoader()); | |
mapping.setAttributeClassification(attributeClassification); | |
mapping.setShouldInlineBinaryData(false); | |
if(mapping.getMimeType() == null) { | |
if(areEquals(paramClass, javax.xml.transform.Source.class)) { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/xml")); | |
} else { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/octet-stream")); | |
} | |
} | |
xmlDescriptor.addMapping(mapping); | |
} else { | |
XMLDirectMapping mapping = new XMLDirectMapping(); | |
mapping.setNullValueMarshalled(true); | |
mapping.setAttributeName("value"); | |
mapping.setGetMethodName("getValue"); | |
mapping.setSetMethodName("setValue"); | |
mapping.setXPath("text()"); | |
Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(factoryMethodParamTypes[0], getClass().getClassLoader()); | |
mapping.setAttributeClassification(attributeClassification); | |
xmlDescriptor.addMapping(mapping); | |
} | |
}else if(paramClass.isEnum()){ | |
EnumTypeInfo enumInfo = (EnumTypeInfo)typeInfo.get(paramClass.getQualifiedName()); | |
XMLDirectMapping mapping = new XMLDirectMapping(); | |
mapping.setConverter(buildJAXBEnumTypeConverter(mapping, enumInfo)); | |
mapping.setNullValueMarshalled(true); | |
mapping.setAttributeName("value"); | |
mapping.setGetMethodName("getValue"); | |
mapping.setSetMethodName("setValue"); | |
mapping.setXPath("text()"); | |
Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(factoryMethodParamTypes[0], getClass().getClassLoader()); | |
mapping.setAttributeClassification(attributeClassification); | |
xmlDescriptor.addMapping(mapping); | |
}else{ | |
XMLCompositeObjectMapping mapping = new XMLCompositeObjectMapping(); | |
mapping.setAttributeName("value"); | |
mapping.setGetMethodName("getValue"); | |
mapping.setSetMethodName("setValue"); | |
mapping.setXPath("."); | |
mapping.setReferenceClassName(factoryMethodParamTypes[0]); | |
xmlDescriptor.addMapping(mapping); | |
} | |
xmlDescriptor.setNamespaceResolver(nsr); | |
setSchemaContext(xmlDescriptor, info); | |
project.addDescriptor(xmlDescriptor); | |
info.setDescriptor(xmlDescriptor); | |
} | |
private void setSchemaContext(XMLDescriptor desc, TypeInfo info) { | |
XMLSchemaClassPathReference schemaRef = new XMLSchemaClassPathReference(); | |
if (info.getClassNamespace() == null || info.getClassNamespace().equals("")) { | |
schemaRef.setSchemaContext("/" + info.getSchemaTypeName()); | |
schemaRef.setSchemaContextAsQName(new QName(info.getSchemaTypeName())); | |
} else { | |
String prefix = desc.getNonNullNamespaceResolver().resolveNamespaceURI(info.getClassNamespace()); | |
if (prefix != null && !prefix.equals("")) { | |
schemaRef.setSchemaContext("/" + prefix + ":" + info.getSchemaTypeName()); | |
schemaRef.setSchemaContextAsQName(new QName(info.getClassNamespace(), info.getSchemaTypeName(), prefix)); | |
} else { | |
String generatedPrefix =getPrefixForNamespace(info.getClassNamespace(), desc.getNonNullNamespaceResolver(), null, false); | |
schemaRef.setSchemaContext("/" + getQualifiedString(generatedPrefix, info.getSchemaTypeName())); | |
if(generatedPrefix == null || generatedPrefix.equals(XMLConstants.EMPTY_STRING)){ | |
schemaRef.setSchemaContextAsQName(new QName(info.getClassNamespace(), info.getSchemaTypeName())); | |
}else{ | |
schemaRef.setSchemaContextAsQName(new QName(info.getClassNamespace(), info.getSchemaTypeName(), generatedPrefix)); | |
} | |
} | |
} | |
// the default type is complex; need to check for simple type case | |
if (info.isEnumerationType() || (info.getPropertyNames().size() == 1 && helper.isAnnotationPresent(info.getProperties().get(info.getPropertyNames().get(0)).getElement(), XmlValue.class))) { | |
schemaRef.setType(XMLSchemaReference.SIMPLE_TYPE); | |
} | |
desc.setSchemaReference(schemaRef); | |
} | |
/** | |
* Generate a mapping for a given Property. | |
* | |
* @param property | |
* @param descriptor | |
* @param namespaceInfo | |
* @return newly created mapping | |
*/ | |
public DatabaseMapping generateMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
if (property.isSetXmlJavaTypeAdapter()) { | |
// if we are dealing with a reference, generate mapping and return | |
if (property.isReference()) { | |
return generateMappingForReferenceProperty(property, descriptor, namespaceInfo); | |
} | |
XmlJavaTypeAdapter xja = property.getXmlJavaTypeAdapter(); | |
JavaClass adapterClass = helper.getJavaClass(xja.getValue()); | |
JavaClass valueType = null; | |
String sValType = xja.getValueType(); | |
if (sValType.equals("javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT")) { | |
valueType = property.getActualType(); | |
} else { | |
valueType = helper.getJavaClass(xja.getValueType()); | |
} | |
DatabaseMapping mapping; | |
boolean isArray = property.getType().isArray() && !property.getType().getRawName().equals("byte[]"); | |
// if the value type is something we have a descriptor for, create | |
// a composite mapping | |
if (typeInfo.containsKey(valueType.getQualifiedName())) { | |
TypeInfo reference = typeInfo.get(valueType.getQualifiedName()); | |
if (isCollectionType(property)) { | |
if (reference.isEnumerationType()) { | |
mapping = generateEnumCollectionMapping(property, descriptor, namespaceInfo, (EnumTypeInfo) reference); | |
XMLJavaTypeConverter converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName()); | |
converter.setNestedConverter(((XMLCompositeDirectCollectionMapping)mapping).getValueConverter()); | |
((XMLCompositeDirectCollectionMapping)mapping).setValueConverter(converter); | |
} else { | |
mapping = generateCompositeCollectionMapping(property, descriptor, namespaceInfo, valueType.getQualifiedName()); | |
((XMLCompositeCollectionMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
} else { | |
if (reference.isEnumerationType()) { | |
mapping = generateDirectEnumerationMapping(property, descriptor, namespaceInfo, (EnumTypeInfo) reference); | |
XMLJavaTypeConverter converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName()); | |
converter.setNestedConverter(((XMLDirectMapping)mapping).getConverter()); | |
((XMLDirectMapping)mapping).setConverter(converter); | |
} else { | |
mapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, valueType.getQualifiedName()); | |
((XMLCompositeObjectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
} | |
} else { | |
// no descriptor for value type | |
if (property.isAny()) { | |
if (isCollectionType(property)){ | |
mapping = generateAnyCollectionMapping(property, descriptor, namespaceInfo, property.isMixedContent()); | |
((XMLAnyCollectionMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} else { | |
mapping = generateAnyObjectMapping(property, descriptor, namespaceInfo); | |
((XMLAnyObjectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
} else if (isCollectionType(property) || isArray) { | |
if (property.isSwaAttachmentRef() || property.isMtomAttachment()) { | |
mapping = generateBinaryDataCollectionMapping(property, descriptor, namespaceInfo); | |
((XMLBinaryDataCollectionMapping) mapping).setValueConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} else{ | |
mapping = generateDirectCollectionMapping(property, descriptor, namespaceInfo); | |
if(adapterClass.getQualifiedName().equals(CollapsedStringAdapter.class.getName())) { | |
((XMLCompositeDirectCollectionMapping)mapping).setCollapsingStringValues(true); | |
} else if(adapterClass.getQualifiedName().equals(NormalizedStringAdapter.class.getName())) { | |
((XMLCompositeDirectCollectionMapping)mapping).setNormalizingStringValues(true); | |
} else { | |
((XMLCompositeDirectCollectionMapping) mapping).setValueConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
} | |
} else if (property.isSwaAttachmentRef() || property.isMtomAttachment()) { | |
mapping = generateBinaryMapping(property, descriptor, namespaceInfo); | |
((XMLBinaryDataMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} else { | |
if (!property.isAttribute() && areEquals(valueType, Object.class)){ | |
mapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, null); | |
((XMLCompositeObjectMapping)mapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
((XMLCompositeObjectMapping)mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
return mapping; | |
} | |
mapping = generateDirectMapping(property, descriptor, namespaceInfo); | |
if(adapterClass.getQualifiedName().equals(CollapsedStringAdapter.class.getName())) { | |
((XMLDirectMapping)mapping).setCollapsingStringValues(true); | |
} else if(adapterClass.getQualifiedName().equals(NormalizedStringAdapter.class.getName())) { | |
((XMLDirectMapping)mapping).setNormalizingStringValues(true); | |
} else { | |
((XMLDirectMapping) mapping).setConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
} | |
} | |
return mapping; | |
} | |
if (property.isSetXmlJoinNodes()) { | |
if (isCollectionType(property)) { | |
return generateXMLCollectionReferenceMapping(property, descriptor, namespaceInfo, property.getActualType()); | |
} | |
return generateXMLObjectReferenceMapping(property, descriptor, namespaceInfo, property.getType()); | |
} | |
if (property.isXmlTransformation()) { | |
return generateTransformationMapping(property, descriptor, namespaceInfo); | |
} | |
if (property.isChoice()) { | |
if (this.isCollectionType(property)) { | |
return generateChoiceCollectionMapping(property, descriptor, namespaceInfo); | |
} | |
return generateChoiceMapping(property, descriptor, namespaceInfo); | |
} | |
if (property.isInverseReference()) { | |
return generateInverseReferenceMapping(property, descriptor, namespaceInfo); | |
} | |
if (property.isAny()) { | |
if (isCollectionType(property) || property.getType().isArray()){ | |
return generateAnyCollectionMapping(property, descriptor, namespaceInfo, property.isMixedContent()); | |
} | |
return generateAnyObjectMapping(property, descriptor, namespaceInfo); | |
} | |
if (property.isReference()) { | |
return generateMappingForReferenceProperty(property, descriptor, namespaceInfo); | |
} | |
if (property.isMap()){ | |
if (property.isAnyAttribute()) { | |
return generateAnyAttributeMapping(property, descriptor, namespaceInfo); | |
} | |
return generateMapMapping(property, descriptor, namespaceInfo); | |
} | |
if (isCollectionType(property)) { | |
return generateCollectionMapping(property, descriptor, namespaceInfo); | |
} | |
JavaClass referenceClass = property.getType(); | |
String referenceClassName = referenceClass.getRawName(); | |
if (referenceClass.isArray() && !referenceClassName.equals("byte[]")){ | |
JavaClass componentType = referenceClass.getComponentType(); | |
TypeInfo reference = typeInfo.get(componentType.getName()); | |
if (reference != null && reference.isEnumerationType()) { | |
return generateEnumCollectionMapping(property, descriptor, namespaceInfo,(EnumTypeInfo) reference); | |
} | |
if (areEquals(componentType, Object.class)){ | |
XMLCompositeCollectionMapping mapping = generateCompositeCollectionMapping(property, descriptor, namespaceInfo, null); | |
mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
return mapping; | |
} | |
if (reference != null || componentType.isArray()){ | |
return generateCompositeCollectionMapping(property, descriptor, namespaceInfo, componentType.getQualifiedName()); | |
} | |
return generateDirectCollectionMapping(property, descriptor, namespaceInfo); | |
} | |
if (property.isXmlIdRef()) { | |
return generateXMLObjectReferenceMapping(property, descriptor, namespaceInfo, referenceClass); | |
} | |
TypeInfo reference = typeInfo.get(referenceClass.getQualifiedName()); | |
if (reference != null) { | |
if (reference.isEnumerationType()) { | |
return generateDirectEnumerationMapping(property, descriptor, namespaceInfo, (EnumTypeInfo) reference); | |
} | |
if (property.isXmlLocation()) { | |
XMLCompositeObjectMapping locationMapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, referenceClass.getQualifiedName()); | |
reference.getDescriptor().setInstantiationPolicy(new NullInstantiationPolicy()); | |
descriptor.setLocationAccessor(locationMapping.getAttributeAccessor()); | |
return locationMapping; | |
} else { | |
return generateCompositeObjectMapping(property, descriptor, namespaceInfo, referenceClass.getQualifiedName()); | |
} | |
} | |
if (property.isSwaAttachmentRef() || property.isMtomAttachment()) { | |
return generateBinaryMapping(property, descriptor, namespaceInfo); | |
} | |
if (referenceClass.getQualifiedName().equals(OBJECT_CLASS_NAME) && !property.isAttribute() ) { | |
XMLCompositeObjectMapping coMapping = generateCompositeObjectMapping(property, descriptor, namespaceInfo, null); | |
coMapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
return coMapping; | |
} | |
if (property.isXmlLocation()) { | |
return null; | |
} | |
return generateDirectMapping(property, descriptor, namespaceInfo); | |
} | |
private XMLInverseReferenceMapping generateInverseReferenceMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespace) { | |
XMLInverseReferenceMapping invMapping = new XMLInverseReferenceMapping(); | |
if (isCollectionType(property.getType())) { | |
invMapping.setReferenceClassName(property.getGenericType().getQualifiedName()); | |
} else { | |
invMapping.setReferenceClassName(property.getType().getQualifiedName()); | |
} | |
invMapping.setAttributeName(property.getPropertyName()); | |
String setMethodName = property.getInverseReferencePropertySetMethodName(); | |
String getMethodName = property.getInverseReferencePropertyGetMethodName(); | |
if (setMethodName != null && !setMethodName.equals(XMLConstants.EMPTY_STRING)) { | |
invMapping.setSetMethodName(setMethodName); | |
} | |
if (getMethodName != null && !getMethodName.equals(XMLConstants.EMPTY_STRING)) { | |
invMapping.setGetMethodName(getMethodName); | |
} | |
invMapping.setMappedBy(property.getInverseReferencePropertyName()); | |
if (isCollectionType(property.getType())) { | |
JavaClass collectionType = property.getType(); | |
collectionType = containerClassImpl(collectionType); | |
invMapping.useCollectionClass(helper.getClassForJavaClass(collectionType)); | |
} | |
return invMapping; | |
} | |
/** | |
* Generate an XMLTransformationMapping based on a given Property. | |
* | |
* @param property | |
* @param descriptor | |
* @param namespace | |
* @return | |
*/ | |
public XMLTransformationMapping generateTransformationMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespace) { | |
XMLTransformationMapping mapping = new XMLTransformationMapping(); | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// handle transformation | |
if (property.isSetXmlTransformation()) { | |
XmlTransformation xmlTransformation = property.getXmlTransformation(); | |
mapping.setIsOptional(xmlTransformation.isOptional()); | |
// handle transformer(s) | |
if (xmlTransformation.isSetXmlReadTransformer()) { | |
// handle read transformer | |
mapping.setAttributeName(property.getPropertyName()); | |
XmlReadTransformer readTransformer = xmlTransformation.getXmlReadTransformer(); | |
if (readTransformer.isSetTransformerClass()) { | |
mapping.setAttributeTransformerClassName(xmlTransformation.getXmlReadTransformer().getTransformerClass()); | |
} else { | |
mapping.setAttributeTransformation(xmlTransformation.getXmlReadTransformer().getMethod()); | |
} | |
} | |
if (xmlTransformation.isSetXmlWriteTransformers()) { | |
// handle write transformer(s) | |
for (XmlWriteTransformer writeTransformer : xmlTransformation.getXmlWriteTransformer()) { | |
if (writeTransformer.isSetTransformerClass()) { | |
mapping.addFieldTransformerClassName(writeTransformer.getXmlPath(), writeTransformer.getTransformerClass()); | |
} else { | |
mapping.addFieldTransformation(writeTransformer.getXmlPath(), writeTransformer.getMethod()); | |
} | |
} | |
} | |
} | |
return mapping; | |
} | |
public XMLChoiceObjectMapping generateChoiceMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespace) { | |
XMLChoiceObjectMapping mapping = new XMLChoiceObjectMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
boolean isIdRef = property.isXmlIdRef(); | |
Iterator<Property> choiceProperties = property.getChoiceProperties().iterator(); | |
while (choiceProperties.hasNext()) { | |
Property next = choiceProperties.next(); | |
JavaClass type = next.getType(); | |
JavaClass originalType = next.getType(); | |
Converter converter = null; | |
TypeInfo info = typeInfo.get(type.getName()); | |
if(info != null){ | |
XmlJavaTypeAdapter adapter = info.getXmlJavaTypeAdapter(); | |
if(adapter != null){ | |
String adapterValue = adapter.getValue(); | |
JavaClass adapterClass = helper.getJavaClass(adapterValue); | |
JavaClass theClass = CompilerHelper.getTypeFromAdapterClass(adapterClass, helper); | |
type = theClass; | |
converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName()); | |
} | |
} | |
if (next.getXmlJoinNodes() != null) { | |
// handle XmlJoinNodes | |
List<XMLField> srcFlds = new ArrayList<XMLField>(); | |
List<XMLField> tgtFlds = new ArrayList<XMLField>(); | |
for (XmlJoinNode xmlJoinNode: next.getXmlJoinNodes().getXmlJoinNode()) { | |
srcFlds.add(new XMLField(xmlJoinNode.getXmlPath())); | |
tgtFlds.add(new XMLField(xmlJoinNode.getReferencedXmlPath())); | |
} | |
mapping.addChoiceElement(srcFlds, type.getQualifiedName(), tgtFlds); | |
} else if (isIdRef) { | |
// handle IDREF | |
String tgtXPath = null; | |
TypeInfo referenceType = typeInfo.get(type.getQualifiedName()); | |
if (null != referenceType && referenceType.isIDSet()) { | |
Property prop = referenceType.getIDProperty(); | |
tgtXPath = getXPathForField(prop, namespace, !prop.isAttribute()).getXPath(); | |
} | |
// if the XPath is set (via xml-path) use it, otherwise figure it out | |
XMLField srcXPath; | |
if (next.getXmlPath() != null) { | |
srcXPath = new XMLField(next.getXmlPath()); | |
} else { | |
srcXPath = getXPathForField(next, namespace, true); | |
} | |
mapping.addChoiceElement(srcXPath.getXPath(), type.getQualifiedName(), tgtXPath); | |
} else { | |
XMLField xpath; | |
if (next.getXmlPath() != null) { | |
xpath = new XMLField(next.getXmlPath()); | |
} else { | |
xpath = getXPathForField(next, namespace, (!(this.typeInfo.containsKey(type.getQualifiedName()))) || next.isMtomAttachment() || type.isEnum()); | |
} | |
mapping.addChoiceElement(xpath, type.getQualifiedName()); | |
if(!originalType.getQualifiedName().equals(type.getQualifiedName())) { | |
if(mapping.getClassNameToFieldMappings().get(originalType.getQualifiedName()) == null) { | |
mapping.getClassNameToFieldMappings().put(originalType.getQualifiedName(), xpath); | |
} | |
mapping.addConverter(xpath, converter); | |
} | |
if (type.isEnum()) { | |
DatabaseMapping nestedMapping = (DatabaseMapping) mapping.getChoiceElementMappings().get(xpath); | |
if(nestedMapping.isAbstractDirectMapping()) { | |
((XMLDirectMapping)nestedMapping).setConverter(buildJAXBEnumTypeConverter(nestedMapping, (EnumTypeInfo)info)); | |
} | |
} | |
} | |
} | |
return mapping; | |
} | |
public XMLChoiceCollectionMapping generateChoiceCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespace) { | |
XMLChoiceCollectionMapping mapping = new XMLChoiceCollectionMapping(); | |
initializeXMLContainerMapping(mapping); | |
mapping.setAttributeName(property.getPropertyName()); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
JavaClass collectionType = property.getType(); | |
collectionType = containerClassImpl(collectionType); | |
mapping.useCollectionClassName(collectionType.getRawName()); | |
if (property.isSetXmlElementWrapper()) { | |
mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property)); | |
} | |
boolean isIdRef = property.isXmlIdRef(); | |
Iterator<Property> choiceProperties = property.getChoiceProperties().iterator(); | |
while (choiceProperties.hasNext()) { | |
Property next = choiceProperties.next(); | |
JavaClass type = next.getType(); | |
JavaClass originalType = next.getType(); | |
Converter converter = null; | |
XMLField xmlField = null; | |
TypeInfo info = typeInfo.get(type.getName()); | |
if(info != null){ | |
XmlJavaTypeAdapter adapter = info.getXmlJavaTypeAdapter(); | |
if(adapter != null){ | |
String adapterValue = adapter.getValue(); | |
JavaClass adapterClass = helper.getJavaClass(adapterValue); | |
JavaClass theClass = CompilerHelper.getTypeFromAdapterClass(adapterClass, helper); | |
type = theClass; | |
converter = new XMLJavaTypeConverter(adapterClass.getQualifiedName()); | |
} | |
} | |
if (next.getXmlJoinNodes() != null) { | |
// handle XmlJoinNodes | |
List<XMLField> srcFlds = new ArrayList<XMLField>(); | |
List<XMLField> tgtFlds = new ArrayList<XMLField>(); | |
for (XmlJoinNode xmlJoinNode: next.getXmlJoinNodes().getXmlJoinNode()) { | |
srcFlds.add(new XMLField(xmlJoinNode.getXmlPath())); | |
tgtFlds.add(new XMLField(xmlJoinNode.getReferencedXmlPath())); | |
} | |
mapping.addChoiceElement(srcFlds, type.getQualifiedName(), tgtFlds); | |
} else if (isIdRef) { | |
// handle IDREF | |
String tgtXPath = null; | |
TypeInfo referenceType = typeInfo.get(type.getQualifiedName()); | |
if (null != referenceType && referenceType.isIDSet()) { | |
Property prop = referenceType.getIDProperty(); | |
tgtXPath = getXPathForField(prop, namespace, !prop.isAttribute()).getXPath(); | |
} | |
// if the XPath is set (via xml-path) use it, otherwise figure it out | |
XMLField srcXPath; | |
if (next.getXmlPath() != null) { | |
srcXPath = new XMLField(next.getXmlPath()); | |
} else { | |
srcXPath = getXPathForField(next, namespace, true); | |
} | |
mapping.addChoiceElement(srcXPath.getXPath(), type.getQualifiedName(), tgtXPath); | |
} else { | |
XMLField xpath; | |
if (next.getXmlPath() != null) { | |
xpath = new XMLField(next.getXmlPath()); | |
} else { | |
xpath = getXPathForField(next, namespace, (!(this.typeInfo.containsKey(type.getQualifiedName()))) || type.isEnum()); | |
} | |
xmlField = xpath; | |
mapping.addChoiceElement(xpath.getName(), type.getQualifiedName()); | |
if(!originalType.getQualifiedName().equals(type.getQualifiedName())) { | |
if(mapping.getClassNameToFieldMappings().get(originalType.getQualifiedName()) == null) { | |
mapping.getClassNameToFieldMappings().put(originalType.getQualifiedName(), xpath); | |
} | |
mapping.addConverter(xpath, converter); | |
} | |
} | |
if(xmlField !=null){ | |
DatabaseMapping nestedMapping = (DatabaseMapping) mapping.getChoiceElementMappings().get(xmlField); | |
if(nestedMapping.isAbstractCompositeCollectionMapping()){ | |
// handle null policy set via xml metadata | |
if (property.isSetNullPolicy()) { | |
((XMLCompositeCollectionMapping)nestedMapping).setNullPolicy(getNullPolicyFromProperty(property, namespace.getNamespaceResolverForDescriptor())); | |
} else if (property.isNillable()){ | |
((XMLCompositeCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByXsiNil(true); | |
((XMLCompositeCollectionMapping)nestedMapping).getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
} else if(nestedMapping.isAbstractCompositeDirectCollectionMapping()){ | |
if (next.isSetNullPolicy()) { | |
((XMLCompositeDirectCollectionMapping)nestedMapping).setNullPolicy(getNullPolicyFromProperty(next, namespace.getNamespaceResolverForDescriptor())); | |
} else if (next.isNillable()){ | |
((XMLCompositeDirectCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByXsiNil(true); | |
((XMLCompositeDirectCollectionMapping)nestedMapping).getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
if (type.isEnum()) { | |
((XMLCompositeDirectCollectionMapping)nestedMapping).setValueConverter(buildJAXBEnumTypeConverter(nestedMapping, (EnumTypeInfo)info)); | |
} | |
} else if(nestedMapping instanceof XMLBinaryDataCollectionMapping){ | |
if (next.isSetNullPolicy()) { | |
((XMLBinaryDataCollectionMapping)nestedMapping).setNullPolicy(getNullPolicyFromProperty(next, namespace.getNamespaceResolverForDescriptor())); | |
} else if (next.isNillable()){ | |
((XMLBinaryDataCollectionMapping)nestedMapping).getNullPolicy().setNullRepresentedByXsiNil(true); | |
((XMLBinaryDataCollectionMapping)nestedMapping).getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
} | |
} | |
} | |
return mapping; | |
} | |
public DatabaseMapping generateMappingForReferenceProperty(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
boolean isCollection = isCollectionType(property) || property.getType().isArray(); | |
if (property.isAny()) { | |
return generateAnyCollectionMapping(property, descriptor, namespaceInfo, true); | |
} | |
DatabaseMapping mapping; | |
if (isCollection) { | |
mapping = new XMLChoiceCollectionMapping(); | |
initializeXMLContainerMapping((XMLChoiceCollectionMapping) mapping); | |
JavaClass collectionType = property.getType(); | |
collectionType = containerClassImpl(collectionType); | |
((XMLChoiceCollectionMapping) mapping).useCollectionClassName(collectionType.getRawName()); | |
JAXBElementRootConverter jaxbERConverter = new JAXBElementRootConverter(Object.class); | |
if (property.isSetXmlJavaTypeAdapter()) { | |
JavaClass adapterClass = helper.getJavaClass(property.getXmlJavaTypeAdapter().getValue()); | |
jaxbERConverter.setNestedConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
((XMLChoiceCollectionMapping) mapping).setConverter(jaxbERConverter); | |
if (property.isSetWriteOnly()) { | |
((XMLChoiceCollectionMapping) mapping).setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isSetXmlElementWrapper()) { | |
((XMLChoiceCollectionMapping) mapping).setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property)); | |
} | |
} else { | |
mapping = new XMLChoiceObjectMapping(); | |
JAXBElementRootConverter jaxbERConverter = new JAXBElementRootConverter(Object.class); | |
if (property.isSetXmlJavaTypeAdapter()) { | |
JavaClass adapterClass = helper.getJavaClass(property.getXmlJavaTypeAdapter().getValue()); | |
jaxbERConverter.setNestedConverter(new XMLJavaTypeConverter(adapterClass.getQualifiedName())); | |
} | |
((XMLChoiceObjectMapping) mapping).setConverter(jaxbERConverter); | |
if (property.isSetWriteOnly()) { | |
((XMLChoiceObjectMapping) mapping).setIsWriteOnly(property.isWriteOnly()); | |
} | |
} | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
mapping.setAttributeName(property.getPropertyName()); | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
((XMLMapping)mapping).setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
List<ElementDeclaration> referencedElements = property.getReferencedElements(); | |
JavaClass propertyType = property.getType(); | |
if (propertyType.isArray()) { | |
JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader()); | |
accessor.setComponentClassName(property.getType().getComponentType().getQualifiedName()); | |
JavaClass componentType = propertyType.getComponentType(); | |
if(componentType.isArray()) { | |
Class adaptedClass = classToGeneratedClasses.get(componentType.getQualifiedName()); | |
accessor.setAdaptedClassName(adaptedClass.getName()); | |
} | |
mapping.setAttributeAccessor(accessor); | |
} | |
String wrapperXPath = ""; | |
// handle XmlElementWrapper | |
if (property.isSetXmlElementWrapper()) { | |
XmlElementWrapper wrapper = property.getXmlElementWrapper(); | |
String namespace = wrapper.getNamespace(); | |
if (namespace.equals(XMLProcessor.DEFAULT)) { | |
if (namespaceInfo.isElementFormQualified()) { | |
namespace = namespaceInfo.getNamespace(); | |
} else { | |
namespace = ""; | |
} | |
} | |
if (namespace.equals("")) { | |
wrapperXPath += (wrapper.getName() + "/"); | |
} else { | |
String prefix = getPrefixForNamespace(namespace, namespaceInfo.getNamespaceResolver(), null); | |
wrapperXPath += getQualifiedString(prefix, wrapper.getName() + "/"); | |
} | |
} | |
if(property.isMixedContent() && isCollection) { | |
if(wrapperXPath.length() == 0) { | |
((XMLChoiceCollectionMapping)mapping).setMixedContent(true); | |
} else { | |
((XMLChoiceCollectionMapping)mapping).setMixedContent(wrapperXPath.substring(0, wrapperXPath.length() - 1)); | |
} | |
} | |
for (ElementDeclaration element:referencedElements) { | |
QName elementName = element.getElementName(); | |
JavaClass pType = element.getJavaType(); | |
boolean isBinaryType = (areEquals(pType, AnnotationsProcessor.JAVAX_ACTIVATION_DATAHANDLER) || areEquals(pType, byte[].class) || areEquals(pType, Image.class) || areEquals(pType, Source.class) || areEquals(pType, AnnotationsProcessor.JAVAX_MAIL_INTERNET_MIMEMULTIPART)); | |
boolean isText = pType.isEnum() || (!isBinaryType && !(this.typeInfo.containsKey(element.getJavaTypeName())) && !(element.getJavaTypeName().equals(OBJECT_CLASS_NAME))); | |
String xPath = wrapperXPath; | |
XMLField xmlField = this.getXPathForElement(xPath, elementName, namespaceInfo, isText); | |
//ensure byte[] goes to base64 instead of the default hex. | |
if(helper.getXMLToJavaTypeMap().get(element.getJavaType().getRawName()) == XMLConstants.BASE_64_BINARY_QNAME) { | |
xmlField.setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
} | |
if(areEquals(pType, Object.class)) { | |
xmlField.setIsTypedTextField(true); | |
xmlField.setSchemaType(XMLConstants.ANY_TYPE_QNAME); | |
} | |
DatabaseMapping nestedMapping; | |
if(isCollection){ | |
XMLChoiceCollectionMapping xmlChoiceCollectionMapping = (XMLChoiceCollectionMapping) mapping; | |
xmlChoiceCollectionMapping.addChoiceElement(xmlField, element.getJavaTypeName()); | |
nestedMapping = (DatabaseMapping) xmlChoiceCollectionMapping.getChoiceElementMappings().get(xmlField); | |
if(nestedMapping.isAbstractCompositeCollectionMapping()){ | |
((XMLCompositeCollectionMapping)nestedMapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
} | |
if (nestedMapping.isAbstractCompositeDirectCollectionMapping()) { | |
XMLCompositeDirectCollectionMapping nestedCompositeDirectCollectionMapping = (XMLCompositeDirectCollectionMapping) nestedMapping; | |
nestedCompositeDirectCollectionMapping.getNullPolicy().setNullRepresentedByEmptyNode(false); | |
if(pType.isEnum()) { | |
TypeInfo enumTypeInfo = typeInfo.get(pType.getQualifiedName()); | |
nestedCompositeDirectCollectionMapping.setValueConverter(buildJAXBEnumTypeConverter(nestedCompositeDirectCollectionMapping, (EnumTypeInfo) enumTypeInfo)); | |
} | |
} | |
if (element.isList() && nestedMapping.isAbstractCompositeDirectCollectionMapping()) { | |
XMLListConverter listConverter = new XMLListConverter(); | |
listConverter.setObjectClassName(element.getJavaType().getQualifiedName()); | |
((XMLCompositeDirectCollectionMapping)nestedMapping).setValueConverter(listConverter); | |
} | |
} else { | |
XMLChoiceObjectMapping xmlChoiceObjectMapping = (XMLChoiceObjectMapping) mapping; | |
xmlChoiceObjectMapping.addChoiceElement(xmlField, element.getJavaTypeName()); | |
nestedMapping = (DatabaseMapping) xmlChoiceObjectMapping.getChoiceElementMappings().get(xmlField); | |
if(pType.isEnum()) { | |
TypeInfo enumTypeInfo = typeInfo.get(pType.getQualifiedName()); | |
((XMLDirectMapping)nestedMapping).setConverter(buildJAXBEnumTypeConverter(nestedMapping, (EnumTypeInfo) enumTypeInfo)); | |
} | |
if(nestedMapping.isAbstractCompositeObjectMapping()){ | |
((XMLCompositeObjectMapping)nestedMapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
} | |
} | |
if (!element.isXmlRootElement()) { | |
Class scopeClass = element.getScopeClass(); | |
if (scopeClass == javax.xml.bind.annotation.XmlElementDecl.GLOBAL.class){ | |
scopeClass = JAXBElement.GlobalScope.class; | |
} | |
Class declaredType = helper.getClassForJavaClass(element.getJavaType()); | |
JAXBElementConverter converter = new JAXBElementConverter(xmlField, declaredType, scopeClass); | |
if (isCollection){ | |
XMLChoiceCollectionMapping xmlChoiceCollectionMapping = (XMLChoiceCollectionMapping) mapping; | |
Converter originalConverter = xmlChoiceCollectionMapping.getConverter(xmlField); | |
converter.setNestedConverter(originalConverter); | |
xmlChoiceCollectionMapping.addConverter(xmlField, converter); | |
} else { | |
XMLChoiceObjectMapping xmlChoiceObjectMapping = (XMLChoiceObjectMapping) mapping; | |
Converter originalConverter = xmlChoiceObjectMapping.getConverter(xmlField); | |
converter.setNestedConverter(originalConverter); | |
xmlChoiceObjectMapping.addConverter(xmlField, converter); | |
} | |
} | |
} | |
return mapping; | |
} | |
public XMLAnyCollectionMapping generateAnyCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, boolean isMixed) { | |
XMLAnyCollectionMapping mapping = new XMLAnyCollectionMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// if the XPath is set (via xml-path) use it | |
if (property.getXmlPath() != null) { | |
mapping.setField(new XMLField(property.getXmlPath())); | |
} else { | |
if (property.isSetXmlElementWrapper()) { | |
mapping.setField(getXPathForField(property, namespaceInfo, false, true)); | |
} | |
} | |
if (property.isSetXmlElementWrapper()) { | |
mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property)); | |
} | |
Class declaredType = helper.getClassForJavaClass(property.getActualType()); | |
JAXBElementRootConverter jaxbElementRootConverter = new JAXBElementRootConverter(declaredType); | |
mapping.setConverter(jaxbElementRootConverter); | |
if (property.getDomHandlerClassName() != null) { | |
jaxbElementRootConverter.setNestedConverter(new DomHandlerConverter(property.getDomHandlerClassName())); | |
} | |
if (property.isLax() || property.isReference()) { | |
mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
} else { | |
mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT); | |
} | |
mapping.setMixedContent(isMixed); | |
if (isMixed) { | |
mapping.setPreserveWhitespaceForMixedContent(true); | |
} | |
mapping.setUseXMLRoot(true); | |
JavaClass collectionType = property.getType(); | |
if (collectionType.isArray()){ | |
JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader()); | |
JavaClass componentType = collectionType.getComponentType(); | |
if(componentType.isArray()) { | |
JavaClass baseComponentType = getBaseComponentType(componentType); | |
if (baseComponentType.isPrimitive()){ | |
Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName()); | |
accessor.setComponentClass(primitiveClass); | |
} else { | |
accessor.setComponentClassName(baseComponentType.getQualifiedName()); | |
} | |
} else { | |
accessor.setComponentClassName(componentType.getQualifiedName()); | |
} | |
mapping.setAttributeAccessor(accessor); | |
} | |
collectionType = containerClassImpl(collectionType); | |
mapping.useCollectionClass(helper.getClassForJavaClass(collectionType)); | |
return mapping; | |
} | |
public XMLCompositeObjectMapping generateCompositeObjectMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, String referenceClassName) { | |
XMLCompositeObjectMapping mapping = new XMLCompositeObjectMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
if (!property.isXmlLocation()) { | |
mapping.setIsWriteOnly(true); | |
} | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// if the XPath is set (via xml-path) use it; otherwise figure it out | |
mapping.setXPath(getXPathForField(property, namespaceInfo, false).getXPath()); | |
// handle null policy set via xml metadata | |
if (property.isSetNullPolicy()) { | |
mapping.setNullPolicy(getNullPolicyFromProperty(property, namespaceInfo.getNamespaceResolverForDescriptor())); | |
} else if (property.isNillable()){ | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
if (referenceClassName == null){ | |
((XMLField)mapping.getField()).setIsTypedTextField(true); | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.ANY_TYPE_QNAME); | |
String defaultValue = property.getDefaultValue(); | |
if (null != defaultValue) { | |
mapping.setConverter(new DefaultElementConverter(defaultValue)); | |
} | |
} else { | |
mapping.setReferenceClassName(referenceClassName); | |
} | |
if (property.getInverseReferencePropertyName() != null) { | |
mapping.setContainerAttributeName(property.getInverseReferencePropertyName()); | |
JavaClass backPointerPropertyType = null; | |
JavaClass referenceClass = property.getActualType(); | |
if (property.getInverseReferencePropertyGetMethodName() != null && property.getInverseReferencePropertySetMethodName() != null && !property.getInverseReferencePropertyGetMethodName().equals("") && !property.getInverseReferencePropertySetMethodName().equals("")) { | |
mapping.setContainerGetMethodName(property.getInverseReferencePropertySetMethodName()); | |
mapping.setContainerSetMethodName(property.getInverseReferencePropertySetMethodName()); | |
JavaMethod getMethod = referenceClass.getDeclaredMethod(mapping.getContainerGetMethodName(), new JavaClass[]{}); | |
if (getMethod != null) { | |
backPointerPropertyType = getMethod.getReturnType(); | |
} | |
} else { | |
JavaField backpointerField = referenceClass.getDeclaredField(property.getInverseReferencePropertyName()); | |
if(backpointerField != null) { | |
backPointerPropertyType = backpointerField.getResolvedType(); | |
} | |
} | |
if (isCollectionType(backPointerPropertyType)) { | |
mapping.getInverseReferenceMapping().setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); | |
} | |
} | |
if (property.isRequired()) { | |
((XMLField) mapping.getField()).setRequired(true); | |
} | |
return mapping; | |
} | |
public XMLDirectMapping generateDirectMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLDirectMapping mapping = new XMLDirectMapping(); | |
mapping.setNullValueMarshalled(true); | |
mapping.setAttributeName(property.getPropertyName()); | |
String fixedValue = property.getFixedValue(); | |
if (fixedValue != null) { | |
mapping.setIsWriteOnly(true); | |
} | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// if the XPath is set (via xml-path) use it; otherwise figure it out | |
XMLField xmlField = getXPathForField(property, namespaceInfo, true); | |
mapping.setField(xmlField); | |
if (property.getDefaultValue() != null) { | |
mapping.setNullValue(property.getDefaultValue()); | |
} | |
if (property.isXmlId()) { | |
mapping.setCollapsingStringValues(true); | |
} | |
// handle null policy set via xml metadata | |
if (property.isSetNullPolicy()) { | |
mapping.setNullPolicy(getNullPolicyFromProperty(property, namespaceInfo.getNamespaceResolverForDescriptor())); | |
} else { | |
if (property.isNillable()){ | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
mapping.getNullPolicy().setNullRepresentedByEmptyNode(false); | |
if (!mapping.getXPath().equals("text()")) { | |
((NullPolicy) mapping.getNullPolicy()).setSetPerformedForAbsentNode(false); | |
} | |
} | |
if (property.isRequired()) { | |
((XMLField) mapping.getField()).setRequired(true); | |
} | |
if (property.getType() != null) { | |
String theClass = null; | |
if (property.isSetXmlJavaTypeAdapter()) { | |
theClass = property.getOriginalType().getQualifiedName(); | |
} else { | |
theClass = property.getType().getQualifiedName(); | |
} | |
// Try to get the actual Class | |
try { | |
JavaClass actualJavaClass = helper.getJavaClass(theClass); | |
Class actualClass = helper.getClassForJavaClass(actualJavaClass); | |
mapping.setAttributeClassification(actualClass); | |
} catch (Exception e) { | |
// Couldn't find Class (Dynamic?), so set class name instead. | |
mapping.setAttributeClassificationName(theClass); | |
} | |
} | |
if (XMLConstants.QNAME_QNAME.equals(property.getSchemaType())){ | |
((XMLField) mapping.getField()).setSchemaType(XMLConstants.QNAME_QNAME); | |
} | |
// handle cdata set via metadata | |
if (property.isSetCdata()) { | |
mapping.setIsCDATA(property.isCdata()); | |
} | |
return mapping; | |
} | |
public XMLBinaryDataMapping generateBinaryMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLBinaryDataMapping mapping = new XMLBinaryDataMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// if the XPath is set (via xml-path) use it | |
mapping.setField(getXPathForField(property, namespaceInfo, false)); | |
if (property.isSwaAttachmentRef()) { | |
((XMLField) mapping.getField()).setSchemaType(XMLConstants.SWA_REF_QNAME); | |
mapping.setSwaRef(true); | |
} else if (property.isMtomAttachment()) { | |
XMLField f = ((XMLField) mapping.getField()); | |
if (!f.getSchemaType().equals(XMLConstants.HEX_BINARY_QNAME)) { | |
f.setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
} | |
} | |
if (property.isInlineBinaryData()) { | |
mapping.setShouldInlineBinaryData(true); | |
} | |
// use a non-dynamic implementation of MimeTypePolicy to wrap the MIME string | |
if (property.getMimeType() != null) { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy(property.getMimeType(), mapping)); | |
} else { | |
if(areEquals(property.getType(), javax.xml.transform.Source.class)) { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/xml", mapping)); | |
} else if(areEquals(property.getType(), java.awt.Image.class)) { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("image/png", mapping)); | |
} else { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/octet-stream", mapping)); | |
} | |
} | |
if (property.isSetNullPolicy()) { | |
mapping.setNullPolicy(getNullPolicyFromProperty(property, namespaceInfo.getNamespaceResolverForDescriptor())); | |
} else { | |
if (property.isNillable()){ | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
mapping.getNullPolicy().setNullRepresentedByEmptyNode(false); | |
if (!mapping.getXPath().equals("text()")) { | |
((NullPolicy) mapping.getNullPolicy()).setSetPerformedForAbsentNode(false); | |
} | |
} | |
mapping.setAttributeClassificationName(property.getActualType().getQualifiedName()); | |
return mapping; | |
} | |
public XMLBinaryDataCollectionMapping generateBinaryDataCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLBinaryDataCollectionMapping mapping = new XMLBinaryDataCollectionMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isSetXmlElementWrapper()) { | |
mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property)); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// handle null policy set via xml metadata | |
if (property.isSetNullPolicy()) { | |
mapping.setNullPolicy(getNullPolicyFromProperty(property, namespaceInfo.getNamespaceResolverForDescriptor())); | |
} else if (property.isNillable()){ | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
// if the XPath is set (via xml-path) use it | |
mapping.setField(getXPathForField(property, namespaceInfo, false)); | |
if (property.isSwaAttachmentRef()) { | |
((XMLField) mapping.getField()).setSchemaType(XMLConstants.SWA_REF_QNAME); | |
mapping.setSwaRef(true); | |
} else if (property.isMtomAttachment()) { | |
((XMLField) mapping.getField()).setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
} | |
if (property.isInlineBinaryData()) { | |
mapping.setShouldInlineBinaryData(true); | |
} | |
// use a non-dynamic implementation of MimeTypePolicy to wrap the MIME string | |
if (property.getMimeType() != null) { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy(property.getMimeType())); | |
} else { | |
if(areEquals(property.getType(), javax.xml.transform.Source.class)) { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/xml")); | |
} else { | |
mapping.setMimeTypePolicy(new FixedMimeTypePolicy("application/octet-stream")); | |
} | |
} | |
JavaClass collectionType = property.getType(); | |
JavaClass itemType = property.getActualType(); | |
if(collectionType != null && isCollectionType(collectionType)){ | |
try{ | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(itemType.getQualifiedName(), false, helper.getClassLoader()); | |
mapping.setAttributeElementClass(declaredClass); | |
}catch (Exception e) { | |
} | |
} | |
collectionType = containerClassImpl(collectionType); | |
mapping.useCollectionClassName(collectionType.getRawName()); | |
return mapping; | |
} | |
public XMLDirectMapping generateDirectEnumerationMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, EnumTypeInfo enumInfo) { | |
XMLDirectMapping mapping = new XMLDirectMapping(); | |
mapping.setNullValueMarshalled(true); | |
mapping.setConverter(buildJAXBEnumTypeConverter(mapping, enumInfo)); | |
mapping.setAttributeName(property.getPropertyName()); | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
mapping.setField(getXPathForField(property, namespaceInfo, true)); | |
if (!mapping.getXPath().equals("text()")) { | |
((NullPolicy) mapping.getNullPolicy()).setSetPerformedForAbsentNode(false); | |
} | |
return mapping; | |
} | |
private JAXBEnumTypeConverter buildJAXBEnumTypeConverter(DatabaseMapping mapping, EnumTypeInfo enumInfo){ | |
JAXBEnumTypeConverter converter = new JAXBEnumTypeConverter(mapping, enumInfo.getClassName(), false); | |
List<String> fieldNames = enumInfo.getFieldNames(); | |
List<Object> xmlEnumValues = enumInfo.getXmlEnumValues(); | |
for (int i=0; i< fieldNames.size(); i++) { | |
converter.addConversionValue(xmlEnumValues.get(i), fieldNames.get(i)); | |
} | |
return converter; | |
} | |
public DatabaseMapping generateCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
// check to see if this should be a composite or direct mapping | |
JavaClass javaClass = property.getActualType(); | |
if (property.isMixedContent()) { | |
return generateAnyCollectionMapping(property, descriptor, namespaceInfo, true); | |
} | |
if (property.isXmlIdRef() || property.isSetXmlJoinNodes()) { | |
return generateXMLCollectionReferenceMapping(property, descriptor, namespaceInfo, javaClass); | |
} | |
if (javaClass != null && typeInfo.get(javaClass.getQualifiedName()) != null) { | |
TypeInfo referenceInfo = typeInfo.get(javaClass.getQualifiedName()); | |
if (referenceInfo.isEnumerationType()) { | |
return generateEnumCollectionMapping(property, descriptor, namespaceInfo,(EnumTypeInfo) referenceInfo); | |
} | |
return generateCompositeCollectionMapping(property, descriptor, namespaceInfo, javaClass.getQualifiedName()); | |
} | |
if (!property.isAttribute() && javaClass != null && javaClass.getQualifiedName().equals(OBJECT_CLASS_NAME)){ | |
XMLCompositeCollectionMapping ccMapping = generateCompositeCollectionMapping(property, descriptor, namespaceInfo, null); | |
ccMapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
return ccMapping; | |
} | |
if(isBinaryData(javaClass)){ | |
return generateBinaryDataCollectionMapping(property, descriptor, namespaceInfo); | |
} | |
return generateDirectCollectionMapping(property, descriptor, namespaceInfo); | |
} | |
public XMLCompositeDirectCollectionMapping generateEnumCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, EnumTypeInfo info) { | |
XMLCompositeDirectCollectionMapping mapping = generateDirectCollectionMapping(property, descriptor, namespaceInfo); | |
mapping.setValueConverter(buildJAXBEnumTypeConverter(mapping, info)); | |
return mapping; | |
} | |
public XMLAnyAttributeMapping generateAnyAttributeMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLAnyAttributeMapping mapping = new XMLAnyAttributeMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// if the XPath is set (via xml-path) use it | |
if (property.getXmlPath() != null) { | |
mapping.setField(new XMLField(property.getXmlPath())); | |
} | |
mapping.setSchemaInstanceIncluded(false); | |
mapping.setNamespaceDeclarationIncluded(false); | |
JavaClass mapType = property.getType(); | |
if (areEquals(mapType, Map.class)) { | |
mapType = jotHashMap; | |
} | |
mapping.useMapClassName(mapType.getRawName()); | |
return mapping; | |
} | |
public XMLAnyObjectMapping generateAnyObjectMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLAnyObjectMapping mapping = new XMLAnyObjectMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// if the XPath is set (via xml-path) use it | |
if (property.getXmlPath() != null) { | |
mapping.setField(new XMLField(property.getXmlPath())); | |
} | |
Class declaredType = helper.getClassForJavaClass(property.getActualType()); | |
JAXBElementRootConverter jaxbElementRootConverter = new JAXBElementRootConverter(declaredType); | |
mapping.setConverter(jaxbElementRootConverter); | |
if (property.getDomHandlerClassName() != null) { | |
jaxbElementRootConverter.setNestedConverter(new DomHandlerConverter(property.getDomHandlerClassName())); | |
} | |
if (property.isLax()) { | |
mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
} else { | |
mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_ALL_AS_ELEMENT); | |
} | |
if (property.isMixedContent()) { | |
mapping.setMixedContent(true); | |
} else { | |
mapping.setUseXMLRoot(true); | |
} | |
return mapping; | |
} | |
protected boolean areEquals(JavaClass src, Class tgt) { | |
if (src == null || tgt == null) { | |
return false; | |
} | |
return src.getRawName().equals(tgt.getCanonicalName()); | |
} | |
/** | |
* Compares a JavaModel JavaClass to a Class. Equality is based on | |
* the raw name of the JavaClass compared to the canonical | |
* name of the Class. | |
* | |
* @param src | |
* @param tgt | |
* @return | |
*/ | |
protected boolean areEquals(JavaClass src, String tgtCanonicalName) { | |
if (src == null || tgtCanonicalName == null) { | |
return false; | |
} | |
return src.getRawName().equals(tgtCanonicalName); | |
} | |
public XMLCompositeCollectionMapping generateMapMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLCompositeCollectionMapping mapping = new XMLCompositeCollectionMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
XMLField field = getXPathForField(property, namespaceInfo, false); | |
JavaClass descriptorClass = helper.getJavaClass(descriptor.getJavaClassName()); | |
JavaClass mapValueClass = helper.getJavaClass(MapValue.class); | |
if(mapValueClass.isAssignableFrom(descriptorClass)){ | |
mapping.setXPath("entry"); | |
}else{ | |
mapping.setXPath(field.getXPath() + "/entry"); | |
} | |
Class generatedClass = generateMapEntryClassAndDescriptor(property, descriptor.getNonNullNamespaceResolver()); | |
mapping.setReferenceClass(generatedClass); | |
String mapClassName = property.getType().getRawName(); | |
mapping.useCollectionClass(ArrayList.class); | |
mapping.setAttributeAccessor(new MapValueAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), generatedClass, mapClassName, helper.getClassLoader())); | |
return mapping; | |
} | |
private Class generateMapEntryClassAndDescriptor(Property property, NamespaceResolver nr){ | |
JavaClass keyType = property.getKeyType(); | |
JavaClass valueType = property.getValueType(); | |
if(keyType == null){ | |
keyType = helper.getJavaClass("java.lang.Object"); | |
} | |
if(valueType == null){ | |
valueType = helper.getJavaClass("java.lang.Object"); | |
} | |
String mapEntryClassName = getJaxbClassLoader().nextAvailableGeneratedClassName(); | |
MapEntryGeneratedKey mapKey = new MapEntryGeneratedKey(keyType.getQualifiedName(),valueType.getQualifiedName()); | |
Class generatedClass = getGeneratedMapEntryClasses().get(mapKey); | |
if(generatedClass == null){ | |
generatedClass = generateMapEntryClass(mapEntryClassName, keyType.getQualifiedName(), valueType.getQualifiedName()); | |
getGeneratedMapEntryClasses().put(mapKey, generatedClass); | |
XMLDescriptor desc = new XMLDescriptor(); | |
desc.setJavaClass(generatedClass); | |
desc.addMapping(generateMappingForType(keyType, Property.DEFAULT_KEY_NAME)); | |
desc.addMapping(generateMappingForType(valueType, Property.DEFAULT_VALUE_NAME)); | |
desc.setNamespaceResolver(nr); | |
project.addDescriptor(desc); | |
} | |
return generatedClass; | |
} | |
private Class generateMapEntryClass(String className, String keyType, String valueType){ | |
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); | |
String qualifiedInternalClassName = className.replace('.', '/'); | |
String qualifiedInternalKeyClassName = keyType.replace('.', '/'); | |
String qualifiedInternalValueClassName = valueType.replace('.', '/'); | |
String sig = "Ljava/lang/Object;Lorg/eclipse/persistence/internal/jaxb/many/MapEntry<L"+qualifiedInternalKeyClassName+";L"+qualifiedInternalValueClassName+";>;"; | |
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, qualifiedInternalClassName, sig, "java/lang/Object", new String[] { "org/eclipse/persistence/internal/jaxb/many/MapEntry" }); | |
cw.visitField(Opcodes.ACC_PRIVATE, "key", "L"+qualifiedInternalKeyClassName+";", null, null); | |
cw.visitField(Opcodes.ACC_PRIVATE, "value", "L"+qualifiedInternalValueClassName+";", null, null); | |
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); | |
mv.visitInsn(Opcodes.RETURN); | |
mv.visitMaxs(1, 1); | |
mv.visitEnd(); | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getKey", "()L"+qualifiedInternalKeyClassName+";", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitFieldInsn(Opcodes.GETFIELD, qualifiedInternalClassName, "key", "L"+qualifiedInternalKeyClassName+";"); | |
mv.visitInsn(Opcodes.ARETURN); | |
mv.visitMaxs(1, 1); | |
mv.visitEnd(); | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setKey", "(L"+qualifiedInternalKeyClassName+";)V", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitVarInsn(Opcodes.ALOAD, 1); | |
mv.visitFieldInsn(Opcodes.PUTFIELD, qualifiedInternalClassName, "key", "L"+qualifiedInternalKeyClassName+";"); | |
mv.visitInsn(Opcodes.RETURN); | |
mv.visitMaxs(2, 2); | |
mv.visitEnd(); | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getValue", "()L"+qualifiedInternalValueClassName+";", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitFieldInsn(Opcodes.GETFIELD, qualifiedInternalClassName, "value", "L"+qualifiedInternalValueClassName+";"); | |
mv.visitInsn(Opcodes.ARETURN); | |
mv.visitMaxs(1, 1); | |
mv.visitEnd(); | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setValue", "(L"+qualifiedInternalValueClassName+";)V", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitVarInsn(Opcodes.ALOAD, 1); | |
mv.visitFieldInsn(Opcodes.PUTFIELD, qualifiedInternalClassName, "value", "L"+qualifiedInternalValueClassName+";"); | |
mv.visitInsn(Opcodes.RETURN); | |
mv.visitMaxs(2, 2); | |
mv.visitEnd(); | |
if(!qualifiedInternalValueClassName.equals("java/lang/Object")){ | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "getValue", "()Ljava/lang/Object;", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "getValue", "()L"+qualifiedInternalValueClassName+";"); | |
mv.visitInsn(Opcodes.ARETURN); | |
mv.visitMaxs(1, 1); | |
mv.visitEnd(); | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "setValue", "(Ljava/lang/Object;)V", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitVarInsn(Opcodes.ALOAD, 1); | |
mv.visitTypeInsn(Opcodes.CHECKCAST, qualifiedInternalValueClassName); | |
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "setValue", "(L"+qualifiedInternalValueClassName+";)V"); | |
mv.visitInsn(Opcodes.RETURN); | |
mv.visitMaxs(2, 2); | |
mv.visitEnd(); | |
} | |
if(!qualifiedInternalKeyClassName.equals("java/lang/Object")){ | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "getKey", "()Ljava/lang/Object;", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,qualifiedInternalClassName, "getKey", "()L"+qualifiedInternalKeyClassName+";"); | |
mv.visitInsn(Opcodes.ARETURN); | |
mv.visitMaxs(1, 1); | |
mv.visitEnd(); | |
mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "setKey", "(Ljava/lang/Object;)V", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitVarInsn(Opcodes.ALOAD, 1); | |
mv.visitTypeInsn(Opcodes.CHECKCAST, qualifiedInternalKeyClassName); | |
mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "setKey", "(L"+qualifiedInternalKeyClassName+";)V"); | |
mv.visitInsn(Opcodes.RETURN); | |
mv.visitMaxs(2, 2); | |
mv.visitEnd(); | |
} | |
cw.visitEnd(); | |
byte[] classBytes =cw.toByteArray(); | |
Class generatedClass = getJaxbClassLoader().generateClass(className, classBytes); | |
return generatedClass; | |
} | |
private DatabaseMapping generateMappingForType(JavaClass theType, String attributeName){ | |
DatabaseMapping mapping; | |
boolean typeIsObject = theType.getRawName().equals(OBJECT_CLASS_NAME); | |
TypeInfo info = typeInfo.get(theType.getQualifiedName()); | |
if ((info != null && !(info.isEnumerationType())) || typeIsObject) { | |
mapping = new XMLCompositeObjectMapping(); | |
mapping.setAttributeName(attributeName); | |
((XMLCompositeObjectMapping)mapping).setXPath(attributeName); | |
if(typeIsObject){ | |
((XMLCompositeObjectMapping)mapping).setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
((XMLField)((XMLCompositeObjectMapping)mapping).getField()).setIsTypedTextField(true); | |
((XMLField)((XMLCompositeObjectMapping)mapping).getField()).setSchemaType(XMLConstants.ANY_TYPE_QNAME); | |
}else{ | |
((XMLCompositeObjectMapping)mapping).setReferenceClassName(theType.getQualifiedName()); | |
} | |
} else { | |
mapping = new XMLDirectMapping(); | |
mapping.setAttributeName(attributeName); | |
((XMLDirectMapping)mapping).setNullValueMarshalled(true); | |
((XMLDirectMapping)mapping).setXPath(attributeName + TXT); | |
QName schemaType = (QName) userDefinedSchemaTypes.get(theType.getQualifiedName()); | |
if (schemaType == null) { | |
schemaType = (QName) helper.getXMLToJavaTypeMap().get(theType); | |
} | |
((XMLField)((XMLDirectMapping)mapping).getField()).setSchemaType(schemaType); | |
if(info != null && info.isEnumerationType()) { | |
((XMLDirectMapping)mapping).setConverter(buildJAXBEnumTypeConverter(mapping, (EnumTypeInfo)info)); | |
} | |
} | |
return mapping; | |
} | |
public XMLCompositeCollectionMapping generateCompositeCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, String referenceClassName) { | |
XMLCompositeCollectionMapping mapping = new XMLCompositeCollectionMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
// handle null policy set via xml metadata | |
if (property.isSetNullPolicy()) { | |
mapping.setNullPolicy(getNullPolicyFromProperty(property, namespaceInfo.getNamespaceResolverForDescriptor())); | |
} else if (property.isNillable()){ | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
if (property.isSetXmlElementWrapper()) { | |
mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property)); | |
} | |
JavaClass collectionType = property.getType(); | |
if (collectionType.isArray()){ | |
JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader()); | |
JavaClass componentType = collectionType.getComponentType(); | |
if(componentType.isArray()) { | |
Class adaptedClass = classToGeneratedClasses.get(componentType.getName()); | |
referenceClassName = adaptedClass.getName(); | |
accessor.setAdaptedClassName(referenceClassName); | |
JavaClass baseComponentType = getBaseComponentType(componentType); | |
if (baseComponentType.isPrimitive()){ | |
Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(baseComponentType.getRawName()); | |
accessor.setComponentClass(primitiveClass); | |
} else { | |
accessor.setComponentClassName(baseComponentType.getQualifiedName()); | |
} | |
} else { | |
accessor.setComponentClassName(componentType.getQualifiedName()); | |
} | |
mapping.setAttributeAccessor(accessor); | |
} | |
collectionType = containerClassImpl(collectionType); | |
mapping.useCollectionClassName(collectionType.getRawName()); | |
// if the XPath is set (via xml-path) use it; otherwise figure it out | |
XMLField xmlField = getXPathForField(property, namespaceInfo, false); | |
mapping.setXPath(xmlField.getXPath()); | |
if (referenceClassName == null){ | |
((XMLField)mapping.getField()).setIsTypedTextField(true); | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.ANY_TYPE_QNAME); | |
} else { | |
mapping.setReferenceClassName(referenceClassName); | |
} | |
if (property.isRequired()) { | |
((XMLField) mapping.getField()).setRequired(true); | |
} | |
if (property.getInverseReferencePropertyName() != null) { | |
mapping.setContainerAttributeName(property.getInverseReferencePropertyName()); | |
JavaClass backPointerPropertyType = null; | |
JavaClass referenceClass = property.getActualType(); | |
if(property.getInverseReferencePropertyGetMethodName() != null && property.getInverseReferencePropertySetMethodName() != null && !property.getInverseReferencePropertyGetMethodName().equals("") && !property.getInverseReferencePropertySetMethodName().equals("")) { | |
mapping.setContainerGetMethodName(property.getInverseReferencePropertySetMethodName()); | |
mapping.setContainerSetMethodName(property.getInverseReferencePropertySetMethodName()); | |
JavaMethod getMethod = referenceClass.getDeclaredMethod(mapping.getContainerGetMethodName(), new JavaClass[]{}); | |
if(getMethod != null) { | |
backPointerPropertyType = getMethod.getReturnType(); | |
} | |
} else { | |
JavaField backpointerField = referenceClass.getDeclaredField(property.getInverseReferencePropertyName()); | |
if (backpointerField != null) { | |
backPointerPropertyType = backpointerField.getResolvedType(); | |
} | |
} | |
if (isCollectionType(backPointerPropertyType)) { | |
mapping.getInverseReferenceMapping().setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); | |
} | |
} | |
return mapping; | |
} | |
public XMLCompositeDirectCollectionMapping generateDirectCollectionMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
XMLCompositeDirectCollectionMapping mapping = new XMLCompositeDirectCollectionMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
JavaClass collectionType = property.getType(); | |
if (collectionType.isArray()){ | |
JAXBArrayAttributeAccessor accessor = new JAXBArrayAttributeAccessor(mapping.getAttributeAccessor(), mapping.getContainerPolicy(), helper.getClassLoader()); | |
String componentClassName = collectionType.getComponentType().getQualifiedName(); | |
if (collectionType.getComponentType().isPrimitive()){ | |
Class primitiveClass = XMLConversionManager.getDefaultManager().convertClassNameToClass(componentClassName); | |
accessor.setComponentClass(primitiveClass); | |
mapping.setAttributeAccessor(accessor); | |
Class declaredClass = XMLConversionManager.getDefaultManager().getObjectClass(primitiveClass); | |
mapping.setAttributeElementClass(declaredClass); | |
} else { | |
accessor.setComponentClassName(componentClassName); | |
mapping.setAttributeAccessor(accessor); | |
JavaClass componentType = collectionType.getComponentType(); | |
try{ | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(componentType.getRawName(), false, helper.getClassLoader()); | |
mapping.setAttributeElementClass(declaredClass); | |
}catch (Exception e) {} | |
} | |
} else if (isCollectionType(collectionType)){ | |
if (collectionType.hasActualTypeArguments()){ | |
JavaClass itemType = (JavaClass)collectionType.getActualTypeArguments().toArray()[0]; | |
try { | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(itemType.getRawName(), false, helper.getClassLoader()); | |
if(declaredClass != String.class){ | |
mapping.setAttributeElementClass(declaredClass); | |
} | |
} catch (Exception e) {} | |
} | |
} | |
collectionType = containerClassImpl(collectionType); | |
mapping.useCollectionClassName(collectionType.getRawName()); | |
// if the XPath is set (via xml-path) use it; otherwise figure it out | |
XMLField xmlField = getXPathForField(property, namespaceInfo, true); | |
mapping.setField(xmlField); | |
if (helper.isAnnotationPresent(property.getElement(), XmlMixed.class)) { | |
xmlField.setXPath("text()"); | |
} | |
if (XMLConstants.QNAME_QNAME.equals(property.getSchemaType())){ | |
((XMLField) mapping.getField()).setSchemaType(XMLConstants.QNAME_QNAME); | |
} | |
// handle null policy set via xml metadata | |
if (property.isSetNullPolicy()) { | |
mapping.setNullPolicy(getNullPolicyFromProperty(property, namespaceInfo.getNamespaceResolverForDescriptor())); | |
} else if (property.isNillable()){ | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
mapping.getNullPolicy().setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
} | |
mapping.getNullPolicy().setNullRepresentedByEmptyNode(false); | |
if (property.isSetXmlElementWrapper()) { | |
mapping.setWrapperNullPolicy(getWrapperNullPolicyFromProperty(property)); | |
} | |
if (property.isRequired()) { | |
((XMLField) mapping.getField()).setRequired(true); | |
} | |
if (property.isXmlElementType() && property.getGenericType()!=null ){ | |
Class theClass = helper.getClassForJavaClass(property.getGenericType()); | |
mapping.setAttributeElementClass(theClass); | |
} | |
if (xmlField.getXPathFragment().isAttribute() || property.isXmlList() || xmlField.getXPathFragment().nameIsText()){ | |
mapping.setUsesSingleNode(true); | |
} | |
// handle cdata set via metadata | |
if (property.isSetCdata()) { | |
mapping.setIsCDATA(property.isCdata()); | |
} | |
return mapping; | |
} | |
public String getPrefixForNamespace(String URI, org.eclipse.persistence.oxm.NamespaceResolver namespaceResolver, String suggestedPrefix) { | |
return getPrefixForNamespace(URI, namespaceResolver, suggestedPrefix, true); | |
} | |
public String getPrefixForNamespace(String URI, org.eclipse.persistence.oxm.NamespaceResolver namespaceResolver, String suggestedPrefix, boolean addPrefixToNR) { | |
String defaultNS = namespaceResolver.getDefaultNamespaceURI(); | |
if(defaultNS != null && URI.equals(defaultNS)){ | |
return null; | |
} | |
Enumeration keys = namespaceResolver.getPrefixes(); | |
while (keys.hasMoreElements()) { | |
String next = (String) keys.nextElement(); | |
String nextUri = namespaceResolver.resolveNamespacePrefix(next); | |
if (nextUri.equals(URI)) { | |
return next; | |
} | |
} | |
if (XMLConstants.XML_NAMESPACE_URL.equals(URI)) { | |
return XMLConstants.XML_NAMESPACE_PREFIX; | |
} | |
String prefix = globalNamespaceResolver.resolveNamespaceURI(URI); | |
if(prefix == null){ | |
if(URI.equals(globalNamespaceResolver.getDefaultNamespaceURI())) { | |
namespaceResolver.setDefaultNamespaceURI(URI); | |
return null; | |
} else if(suggestedPrefix != null){ | |
prefix = globalNamespaceResolver.generatePrefix(suggestedPrefix); | |
}else{ | |
prefix = globalNamespaceResolver.generatePrefix(); | |
} | |
} | |
String nrUri = namespaceResolver.resolveNamespacePrefix(prefix); | |
while(null != nrUri && !URI.equals(nrUri)){ | |
prefix = globalNamespaceResolver.generatePrefix(); | |
nrUri = namespaceResolver.resolveNamespacePrefix(prefix); | |
} | |
if(addPrefixToNR){ | |
namespaceResolver.put(prefix, URI); | |
} | |
globalNamespaceResolver.put(prefix, URI); | |
return prefix; | |
} | |
public boolean isCollectionType(Property field) { | |
JavaClass type = field.getType(); | |
return isCollectionType(type); | |
} | |
public boolean isCollectionType(JavaClass type) { | |
if (helper.getJavaClass(Collection.class).isAssignableFrom(type) | |
|| helper.getJavaClass(List.class).isAssignableFrom(type) | |
|| helper.getJavaClass(Set.class).isAssignableFrom(type)) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* Setup inheritance for abstract superclass. | |
* | |
* NOTE: We currently only handle one level of inheritance in this case. | |
* For multiple levels the code will need to be modified. The logic in | |
* generateMappings() that determines when to copy down inherited | |
* methods from the parent class will need to be changed as well. | |
* | |
* @param jClass | |
*/ | |
private void setupInheritance(JavaClass jClass) { | |
TypeInfo tInfo = typeInfo.get(jClass.getName()); | |
XMLDescriptor descriptor = tInfo.getDescriptor(); | |
if (descriptor == null) { | |
return; | |
} | |
JavaClass superClass = CompilerHelper.getNextMappedSuperClass(jClass, typeInfo, helper); | |
if (superClass == null){ | |
return; | |
} | |
TypeInfo superTypeInfo = typeInfo.get(superClass.getName()); | |
if (superTypeInfo == null){ | |
return; | |
} | |
XMLDescriptor superDescriptor = superTypeInfo.getDescriptor(); | |
if (superDescriptor != null) { | |
XMLSchemaReference sRef = descriptor.getSchemaReference(); | |
if (sRef == null || sRef.getSchemaContext() == null) { | |
return; | |
} | |
JavaClass rootMappedSuperClass = getRootMappedSuperClass(superClass); | |
TypeInfo rootTypeInfo = typeInfo.get(rootMappedSuperClass.getName()); | |
XMLDescriptor rootDescriptor = rootTypeInfo.getDescriptor(); | |
if (rootDescriptor.getNamespaceResolver() == null) { | |
rootDescriptor.setNamespaceResolver(new NamespaceResolver()); | |
} | |
if (rootDescriptor.getInheritancePolicy().getClassIndicatorField() == null) { | |
XMLField classIndicatorField; | |
if (rootTypeInfo.isSetXmlDiscriminatorNode()) { | |
classIndicatorField = new XMLField(rootTypeInfo.getXmlDiscriminatorNode()); | |
} else { | |
classIndicatorField = new XMLField(ATT + "type"); | |
classIndicatorField.getXPathFragment().setNamespaceURI(XMLConstants.SCHEMA_INSTANCE_URL); | |
} | |
rootDescriptor.getInheritancePolicy().setClassIndicatorField(classIndicatorField); | |
} | |
Object sCtx = null; | |
//TypeInfo tInfo = typeInfo.get(jClass.getName()); | |
if (tInfo.isSetXmlDiscriminatorValue()) { | |
sCtx = tInfo.getXmlDiscriminatorValue(); | |
} else if(!tInfo.isAnonymousComplexType()){ | |
sCtx = sRef.getSchemaContextAsQName(); | |
} | |
if(sCtx != null) { | |
descriptor.getInheritancePolicy().setParentClassName(superClass.getName()); | |
rootDescriptor.getInheritancePolicy().addClassNameIndicator(jClass.getName(), sCtx); | |
} | |
Object value = rootDescriptor.getInheritancePolicy().getClassNameIndicatorMapping().get(rootDescriptor.getJavaClassName()); | |
if (value == null){ | |
if (rootTypeInfo.isSetXmlDiscriminatorValue()) { | |
rootDescriptor.getInheritancePolicy().addClassNameIndicator(rootDescriptor.getJavaClassName(), rootTypeInfo.getXmlDiscriminatorValue()); | |
} else { | |
XMLSchemaReference rootSRef = rootDescriptor.getSchemaReference(); | |
if (rootSRef != null && rootSRef.getSchemaContext() != null) { | |
QName rootSCtx = rootSRef.getSchemaContextAsQName(); | |
rootDescriptor.getInheritancePolicy().addClassNameIndicator(rootDescriptor.getJavaClassName(), rootSCtx); | |
} | |
} | |
} | |
rootDescriptor.getInheritancePolicy().setShouldReadSubclasses(true); | |
} | |
} | |
private JavaClass getRootMappedSuperClass(JavaClass javaClass){ | |
JavaClass rootMappedSuperClass = javaClass; | |
JavaClass nextMappedSuperClass = rootMappedSuperClass; | |
while(nextMappedSuperClass != null){ | |
nextMappedSuperClass = CompilerHelper.getNextMappedSuperClass(nextMappedSuperClass, this.typeInfo, helper); | |
if(nextMappedSuperClass == null){ | |
return rootMappedSuperClass; | |
} | |
rootMappedSuperClass = nextMappedSuperClass; | |
} | |
return rootMappedSuperClass; | |
} | |
public void generateMappings() { | |
Iterator javaClasses = this.typeInfo.keySet().iterator(); | |
while (javaClasses.hasNext()) { | |
String next = (String)javaClasses.next(); | |
JavaClass javaClass = helper.getJavaClass(next); | |
TypeInfo info = (TypeInfo) this.typeInfo.get(next); | |
if (info.isEnumerationType()) { | |
continue; | |
} | |
NamespaceInfo namespaceInfo = this.packageToPackageInfoMappings.get(javaClass.getPackageName()).getNamespaceInfo(); | |
XMLDescriptor descriptor = info.getDescriptor(); | |
if (descriptor != null) { | |
generateMappings(info, descriptor, namespaceInfo); | |
} | |
// set primary key fields (if necessary) | |
DatabaseMapping mapping; | |
// handle XmlID | |
if (info.isIDSet()) { | |
mapping = descriptor.getMappingForAttributeName(info.getIDProperty().getPropertyName()); | |
if (mapping != null) { | |
descriptor.addPrimaryKeyField(mapping.getField()); | |
} | |
} | |
// handle XmlKey | |
if (info.hasXmlKeyProperties()) { | |
for (Property keyProp : info.getXmlKeyProperties()) { | |
mapping = descriptor.getMappingForAttributeName(keyProp.getPropertyName()); | |
if (mapping != null) { | |
descriptor.addPrimaryKeyField(mapping.getField()); | |
} | |
} | |
} | |
info.postInitialize(); | |
} | |
} | |
/** | |
* Generate mappings for a given TypeInfo. | |
* | |
* @param info | |
* @param descriptor | |
* @param namespaceInfo | |
*/ | |
public void generateMappings(TypeInfo info, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
if(info.isAnonymousComplexType()) { | |
//may need to generate inherited mappings | |
generateInheritedMappingsForAnonymousType(info, descriptor, namespaceInfo); | |
} | |
List<Property> propertiesInOrder = info.getNonTransientPropertiesInPropOrder(); | |
for (int i = 0; i < propertiesInOrder.size(); i++) { | |
Property next = propertiesInOrder.get(i); | |
if (next != null && (!next.isTransient() || (next.isTransient() && next.isXmlLocation()))) { | |
DatabaseMapping mapping = generateMapping(next, descriptor, namespaceInfo); | |
if (next.isVirtual()) { | |
VirtualAttributeAccessor accessor = new VirtualAttributeAccessor(); | |
accessor.setAttributeName(mapping.getAttributeName()); | |
String getMethod = info.getXmlVirtualAccessMethods().getGetMethod(); | |
String setMethod = info.getXmlVirtualAccessMethods().getSetMethod(); | |
// Check to see if get/set were overridden in the mapping | |
if (mapping.getAttributeAccessor().isMethodAttributeAccessor()) { | |
getMethod = ((MethodAttributeAccessor) mapping.getAttributeAccessor()).getGetMethodName(); | |
setMethod = ((MethodAttributeAccessor) mapping.getAttributeAccessor()).getSetMethodName(); | |
accessor.setValueType(mapping.getAttributeClassification()); | |
} | |
accessor.setGetMethodName(getMethod); | |
accessor.setSetMethodName(setMethod); | |
if (mapping.getAttributeAccessor() instanceof JAXBArrayAttributeAccessor) { | |
JAXBArrayAttributeAccessor jaa = (JAXBArrayAttributeAccessor) mapping.getAttributeAccessor(); | |
jaa.setNestedAccessor(accessor); | |
} else { | |
mapping.setAttributeAccessor(accessor); | |
} | |
} | |
if (mapping != null) { | |
descriptor.addMapping(mapping); | |
} | |
// set user-defined properties if necessary | |
if (next.isSetUserProperties()) { | |
mapping.setProperties(next.getUserProperties()); | |
} | |
//get package info | |
JavaClass jClass = helper.getJavaClass(info.getJavaClassName()); | |
AccessorFactoryWrapper accessorFactory = info.getXmlAccessorFactory(); | |
if(accessorFactory == null) { | |
accessorFactory = info.getPackageLevelXmlAccessorFactory(); | |
} | |
if(accessorFactory != null) { | |
try { | |
Object accessor = CompilerHelper.createAccessorFor(jClass, next, helper, accessorFactory); | |
if(accessor != null) { | |
CustomAccessorAttributeAccessor attributeAccessor = new CustomAccessorAttributeAccessor(accessor); | |
mapping.setAttributeAccessor(attributeAccessor); | |
} | |
} catch(Exception ex) {} | |
} | |
} | |
next.postInitialize(); | |
} | |
} | |
private void generateInheritedMappingsForAnonymousType(TypeInfo info, XMLDescriptor descriptor, NamespaceInfo namespaceInfo) { | |
List<TypeInfo> mappedParents = new ArrayList<TypeInfo>(); | |
JavaClass next = CompilerHelper.getNextMappedSuperClass(helper.getJavaClass(info.getJavaClassName()), typeInfo, helper); | |
while(next != null) { | |
TypeInfo nextInfo = this.typeInfo.get(next.getName()); | |
mappedParents.add(0, nextInfo); | |
next = CompilerHelper.getNextMappedSuperClass(helper.getJavaClass(nextInfo.getJavaClassName()), typeInfo, helper); | |
} | |
for(TypeInfo nextInfo:mappedParents) { | |
List<Property> propertiesInOrder = nextInfo.getNonTransientPropertiesInPropOrder(); | |
for (int i = 0; i < propertiesInOrder.size(); i++) { | |
Property nextProp = propertiesInOrder.get(i); | |
if (nextProp != null){ | |
DatabaseMapping mapping = generateMapping(nextProp, descriptor, namespaceInfo); | |
descriptor.addMapping(mapping); | |
// set user-defined properties if necessary | |
if (nextProp.isSetUserProperties()) { | |
mapping.setProperties(nextProp.getUserProperties()); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Create an XMLCollectionReferenceMapping and add it to the descriptor. | |
* | |
* @param property | |
* @param descriptor | |
* @param namespaceInfo | |
* @param referenceClass | |
*/ | |
public XMLCollectionReferenceMapping generateXMLCollectionReferenceMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, JavaClass referenceClass) { | |
XMLCollectionReferenceMapping mapping = new XMLCollectionReferenceMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
initializeXMLContainerMapping(mapping); | |
mapping.setUsesSingleNode(property.isXmlList() || (property.isAttribute() && (property.getXmlPath() == null || !property.getXmlPath().contains("/")))); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
mapping.setReferenceClassName(referenceClass.getQualifiedName()); | |
JavaClass collectionType = property.getType(); | |
collectionType = containerClassImpl(collectionType); | |
mapping.useCollectionClassName(collectionType.getRawName()); | |
// here we need to setup source/target key field associations | |
if (property.isSetXmlJoinNodes()) { | |
for (XmlJoinNode xmlJoinNode: property.getXmlJoinNodes().getXmlJoinNode()) { | |
validateJoinNode(descriptor.getJavaClassName(), property, xmlJoinNode.getReferencedXmlPath(), referenceClass); | |
mapping.addSourceToTargetKeyFieldAssociation(xmlJoinNode.getXmlPath(), xmlJoinNode.getReferencedXmlPath()); | |
} | |
} else { | |
// here we need to setup source/target key field associations | |
TypeInfo referenceType = typeInfo.get(referenceClass.getQualifiedName()); | |
String tgtXPath = null; | |
if (null != referenceType && referenceType.isIDSet()) { | |
Property prop = referenceType.getIDProperty(); | |
tgtXPath = getXPathForField(prop, namespaceInfo, !prop.isAttribute()).getXPath(); | |
} | |
// if the XPath is set (via xml-path) use it | |
XMLField srcXPath; | |
if (property.getXmlPath() != null) { | |
srcXPath = new XMLField(property.getXmlPath()); | |
} else { | |
srcXPath = getXPathForField(property, namespaceInfo, true); | |
} | |
mapping.addSourceToTargetKeyFieldAssociation(srcXPath.getXPath(), tgtXPath); | |
} | |
if (property.getInverseReferencePropertyName() != null) { | |
mapping.getInverseReferenceMapping().setAttributeName(property.getInverseReferencePropertyName()); | |
JavaClass backPointerPropertyType = null; | |
if (property.getInverseReferencePropertyGetMethodName() != null && property.getInverseReferencePropertySetMethodName() != null && !property.getInverseReferencePropertyGetMethodName().equals("") && !property.getInverseReferencePropertySetMethodName().equals("")) { | |
mapping.getInverseReferenceMapping().setGetMethodName(property.getInverseReferencePropertySetMethodName()); | |
mapping.getInverseReferenceMapping().setSetMethodName(property.getInverseReferencePropertySetMethodName()); | |
JavaMethod getMethod = referenceClass.getDeclaredMethod(mapping.getInverseReferenceMapping().getGetMethodName(), new JavaClass[]{}); | |
if (getMethod != null) { | |
backPointerPropertyType = getMethod.getReturnType(); | |
} | |
} else { | |
JavaField backpointerField = referenceClass.getDeclaredField(property.getInverseReferencePropertyName()); | |
if (backpointerField != null) { | |
backPointerPropertyType = backpointerField.getResolvedType(); | |
} | |
} | |
if (isCollectionType(backPointerPropertyType)) { | |
mapping.getInverseReferenceMapping().setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); | |
} | |
} | |
return mapping; | |
} | |
/** | |
* Create an XMLObjectReferenceMapping and add it to the descriptor. | |
* | |
* @param property | |
* @param descriptor | |
* @param namespaceInfo | |
* @param referenceClass | |
*/ | |
public XMLObjectReferenceMapping generateXMLObjectReferenceMapping(Property property, XMLDescriptor descriptor, NamespaceInfo namespaceInfo, JavaClass referenceClass) { | |
XMLObjectReferenceMapping mapping = new XMLObjectReferenceMapping(); | |
mapping.setAttributeName(property.getPropertyName()); | |
// handle read-only set via metadata | |
if (property.isSetReadOnly()) { | |
mapping.setIsReadOnly(property.isReadOnly()); | |
} | |
// handle write-only set via metadata | |
if (property.isSetWriteOnly()) { | |
mapping.setIsWriteOnly(property.isWriteOnly()); | |
} | |
if (property.isMethodProperty()) { | |
if (property.getGetMethodName() == null) { | |
// handle case of set with no get method | |
String paramTypeAsString = property.getType().getName(); | |
mapping.setAttributeAccessor(new JAXBSetMethodAttributeAccessor(paramTypeAsString, helper.getClassLoader())); | |
mapping.setIsReadOnly(true); | |
mapping.setSetMethodName(property.getSetMethodName()); | |
} else if (property.getSetMethodName() == null) { | |
mapping.setGetMethodName(property.getGetMethodName()); | |
mapping.setIsWriteOnly(true); | |
} else { | |
mapping.setSetMethodName(property.getSetMethodName()); | |
mapping.setGetMethodName(property.getGetMethodName()); | |
} | |
} | |
mapping.setReferenceClassName(referenceClass.getQualifiedName()); | |
// here we need to setup source/target key field associations | |
if (property.isSetXmlJoinNodes()) { | |
for (XmlJoinNode xmlJoinNode: property.getXmlJoinNodes().getXmlJoinNode()) { | |
validateJoinNode(descriptor.getJavaClassName(), property, xmlJoinNode.getReferencedXmlPath(), referenceClass); | |
mapping.addSourceToTargetKeyFieldAssociation(xmlJoinNode.getXmlPath(), xmlJoinNode.getReferencedXmlPath()); | |
} | |
} else { | |
String tgtXPath = null; | |
TypeInfo referenceType = typeInfo.get(referenceClass.getQualifiedName()); | |
if (null != referenceType && referenceType.isIDSet()) { | |
Property prop = referenceType.getIDProperty(); | |
tgtXPath = getXPathForField(prop, namespaceInfo, !prop.isAttribute()).getXPath(); | |
} | |
// if the XPath is set (via xml-path) use it, otherwise figure it out | |
XMLField srcXPath; | |
if (property.getXmlPath() != null) { | |
srcXPath = new XMLField(property.getXmlPath()); | |
} else { | |
srcXPath = getXPathForField(property, namespaceInfo, true); | |
} | |
mapping.addSourceToTargetKeyFieldAssociation(srcXPath.getXPath(), tgtXPath); | |
} | |
if (property.getInverseReferencePropertyName() != null) { | |
mapping.getInverseReferenceMapping().setAttributeName(property.getInverseReferencePropertyName()); | |
JavaClass backPointerPropertyType = null; | |
if (property.getInverseReferencePropertyGetMethodName() != null && property.getInverseReferencePropertySetMethodName() != null && !property.getInverseReferencePropertyGetMethodName().equals("") && !property.getInverseReferencePropertySetMethodName().equals("")) { | |
mapping.getInverseReferenceMapping().setGetMethodName(property.getInverseReferencePropertySetMethodName()); | |
mapping.getInverseReferenceMapping().setSetMethodName(property.getInverseReferencePropertySetMethodName()); | |
JavaMethod getMethod = referenceClass.getDeclaredMethod(mapping.getInverseReferenceMapping().getGetMethodName(), new JavaClass[]{}); | |
if (getMethod != null) { | |
backPointerPropertyType = getMethod.getReturnType(); | |
} | |
} else { | |
JavaField backpointerField = referenceClass.getDeclaredField(property.getInverseReferencePropertyName()); | |
if (backpointerField != null) { | |
backPointerPropertyType = backpointerField.getResolvedType(); | |
} | |
} | |
if (isCollectionType(backPointerPropertyType)) { | |
mapping.getInverseReferenceMapping().setContainerPolicy(ContainerPolicy.buildDefaultPolicy()); | |
} | |
} | |
return mapping; | |
} | |
private void validateJoinNode(String className, Property property, String referencedXmlPath, JavaClass referenceClass) { | |
TypeInfo targetInfo = this.typeInfo.get(referenceClass.getQualifiedName()); | |
NamespaceInfo namespaceInfo = this.packageToPackageInfoMappings.get(referenceClass.getPackageName()).getNamespaceInfo(); | |
Property idProp = targetInfo.getIDProperty(); | |
if(idProp != null) { | |
String idXpath = idProp.getXmlPath(); | |
if(idXpath == null) { | |
idXpath = this.getXPathForField(idProp, namespaceInfo, !idProp.isAttribute()).getXPath(); | |
} | |
if (referencedXmlPath.equals(idXpath)) { | |
return; | |
} | |
} | |
boolean matched = false; | |
if (targetInfo.getXmlKeyProperties() != null) { | |
for (Property xmlkeyProperty : targetInfo.getXmlKeyProperties()) { | |
String keyXpath = xmlkeyProperty.getXmlPath(); | |
if(keyXpath == null) { | |
keyXpath = this.getXPathForField(xmlkeyProperty, namespaceInfo, !xmlkeyProperty.isAttribute()).getXPath(); | |
} | |
if (referencedXmlPath.equals(keyXpath)) { | |
matched = true; | |
break; | |
} | |
} | |
} | |
if (!matched) { | |
throw JAXBException.invalidReferencedXmlPathOnJoin(className, property.getPropertyName(), referenceClass.getQualifiedName(), referencedXmlPath); | |
} | |
} | |
public XMLField getXPathForField(Property property, NamespaceInfo namespaceInfo, boolean isTextMapping) { | |
return this.getXPathForField(property, namespaceInfo, isTextMapping, false); | |
} | |
private String prefixCustomXPath(String unprefixedXPath, Property property, NamespaceInfo nsInfo) { | |
String newXPath = ""; | |
QName schemaName = property.getSchemaName(); | |
String namespace = schemaName.getNamespaceURI(); | |
if (null == namespace || namespace.equals(XMLConstants.EMPTY_STRING)) { | |
return unprefixedXPath; | |
} | |
String prefix = getPrefixForNamespace(namespace, nsInfo.getNamespaceResolverForDescriptor(), null); | |
if (null == prefix) { | |
return unprefixedXPath; | |
} | |
StringTokenizer st = new StringTokenizer(unprefixedXPath, XMLConstants.XPATH_SEPARATOR); | |
while (st.hasMoreTokens()) { | |
String nextToken = st.nextToken(); | |
if (st.hasMoreTokens()) { | |
if (nextToken.lastIndexOf(XMLConstants.COLON) != -1) { | |
// Token already has a user-supplied prefix | |
newXPath += nextToken; | |
} else { | |
newXPath += prefix + XMLConstants.COLON + nextToken; | |
} | |
newXPath += XMLConstants.XPATH_SEPARATOR; | |
} else { | |
// Last token is text() | |
newXPath += nextToken; | |
} | |
} | |
return newXPath; | |
} | |
public XMLField getXPathForField(Property property, NamespaceInfo namespaceInfo, boolean isTextMapping, boolean isAny) { | |
XMLField xmlField = null; | |
String xPath = property.getXmlPath(); | |
if (null != xPath) { | |
String newXPath = prefixCustomXPath(xPath, property, namespaceInfo); | |
xmlField = new XMLField(newXPath); | |
} else { | |
xPath = ""; | |
if (property.isSetXmlElementWrapper()) { | |
XmlElementWrapper wrapper = property.getXmlElementWrapper(); | |
String namespace = wrapper.getNamespace(); | |
if (namespace.equals(XMLProcessor.DEFAULT)) { | |
if (namespaceInfo.isElementFormQualified()) { | |
namespace = namespaceInfo.getNamespace(); | |
} else { | |
namespace = ""; | |
} | |
} | |
if (namespace.equals("")) { | |
xPath += (wrapper.getName() + "/"); | |
} else { | |
String prefix = getPrefixForNamespace(namespace, namespaceInfo.getNamespaceResolverForDescriptor(), null); | |
xPath += getQualifiedString(prefix, wrapper.getName() + "/"); | |
} | |
if (isAny) { | |
xPath = xPath.substring(0, xPath.length() - 1); | |
xmlField = new XMLField(xPath); | |
return xmlField; | |
} | |
} | |
if (property.isAttribute()) { | |
if (property.isSetXmlPath()) { | |
xPath += property.getXmlPath(); | |
} else { | |
QName name = property.getSchemaName(); | |
String namespace = ""; | |
if (namespaceInfo.isAttributeFormQualified()) { | |
namespace = namespaceInfo.getNamespace(); | |
} | |
if (!name.getNamespaceURI().equals("")) { | |
namespace = name.getNamespaceURI(); | |
} | |
if (namespace.equals("")) { | |
xPath += (ATT + name.getLocalPart()); | |
} else { | |
String prefix = getPrefixForNamespace(namespace, namespaceInfo.getNamespaceResolverForDescriptor(), null); | |
xPath += ATT + getQualifiedString(prefix, name.getLocalPart()); | |
} | |
} | |
xmlField = new XMLField(xPath); | |
} else if (property.isXmlValue()) { | |
if(isBinaryData(property.getActualType())){ | |
xmlField = new XMLField("."); | |
}else{ | |
xmlField = new XMLField("text()"); | |
} | |
} else { | |
QName elementName = property.getSchemaName(); | |
xmlField = getXPathForElement(xPath, elementName, namespaceInfo, isTextMapping); | |
} | |
} | |
QName schemaType = (QName) userDefinedSchemaTypes.get(property.getActualType().getQualifiedName()); | |
if (property.getSchemaType() != null) { | |
schemaType = property.getSchemaType(); | |
} | |
if (schemaType == null) { | |
String propertyActualTypeRawName = property.getActualType().getRawName(); | |
if(QName.class.getCanonicalName().equals(propertyActualTypeRawName)) { | |
schemaType = (QName) helper.getXMLToJavaTypeMap().get(propertyActualTypeRawName); | |
} | |
} | |
if(schemaType !=null && !schemaType.equals (XMLConstants.NORMALIZEDSTRING_QNAME)){ | |
xmlField.setSchemaType(schemaType); | |
} | |
return xmlField; | |
} | |
public XMLField getXPathForElement(String path, QName elementName, NamespaceInfo namespaceInfo, boolean isText) { | |
String namespace = ""; | |
if (!elementName.getNamespaceURI().equals(XMLConstants.EMPTY_STRING)) { | |
namespace = elementName.getNamespaceURI(); | |
} | |
if (namespace.equals(XMLConstants.EMPTY_STRING)) { | |
path += elementName.getLocalPart(); | |
if (isText) { | |
path += TXT; | |
} | |
} else { | |
String prefix = getPrefixForNamespace(namespace, namespaceInfo.getNamespaceResolverForDescriptor(), null); | |
path += getQualifiedString(prefix, elementName.getLocalPart()); | |
if (isText) { | |
path += TXT; | |
} | |
} | |
return new XMLField(path); | |
} | |
public Property getXmlValueFieldForSimpleContent(ArrayList<Property> properties) { | |
boolean foundValue = false; | |
boolean foundNonAttribute = false; | |
Property valueField = null; | |
for (Property prop : properties) { | |
if (helper.isAnnotationPresent(prop.getElement(), XmlValue.class)) { | |
foundValue = true; | |
valueField = prop; | |
} else if (!helper.isAnnotationPresent(prop.getElement(), XmlAttribute.class) && !helper.isAnnotationPresent(prop.getElement(), XmlTransient.class) && !prop.isAnyAttribute()) { | |
foundNonAttribute = true; | |
} | |
} | |
if (foundValue && !foundNonAttribute) { | |
return valueField; | |
} | |
return null; | |
} | |
public String getSchemaTypeNameForClassName(String className) { | |
String typeName = Introspector.decapitalize(className.substring(className.lastIndexOf('.') + 1)); | |
return typeName; | |
} | |
public boolean isMapType(Property property) { | |
JavaClass mapCls = helper.getJavaClass(java.util.Map.class); | |
return mapCls.isAssignableFrom(property.getType()); | |
} | |
public void processGlobalElements(Project project) { | |
//Find any global elements for classes we've generated descriptors for, and add them as possible | |
//root elements. | |
if(this.globalElements == null && this.localElements == null) { | |
return; | |
} | |
List<ElementDeclaration> elements = new ArrayList<ElementDeclaration>(); | |
elements.addAll(this.localElements); | |
elements.addAll(this.globalElements.values()); | |
for(ElementDeclaration nextElement:elements) { | |
QName next = nextElement.getElementName(); | |
String nextClassName = nextElement.getJavaTypeName(); | |
TypeInfo type = this.typeInfo.get(nextClassName); | |
if(helper.isBuiltInJavaType(nextElement.getJavaType()) || (type !=null && type.isEnumerationType())){ | |
//generate a class/descriptor for this element | |
String attributeTypeName = nextClassName; | |
if(nextElement.getJavaType().isPrimitive()) { | |
attributeTypeName = helper.getClassForJavaClass(nextElement.getJavaType()).getName(); | |
} | |
if (nextElement.getAdaptedJavaTypeName() != null) { | |
attributeTypeName = nextElement.getAdaptedJavaTypeName(); | |
} | |
if(next == null){ | |
if(isBinaryData(nextElement.getJavaType())){ | |
Class generatedClass = addByteArrayWrapperAndDescriptor(type, nextElement.getJavaType().getRawName(), nextElement,nextClassName, attributeTypeName); | |
this.qNamesToGeneratedClasses.put(next, generatedClass); | |
if(nextElement.getTypeMappingInfo() != null) { | |
typeMappingInfoToGeneratedClasses.put(nextElement.getTypeMappingInfo(), generatedClass); | |
} | |
try{ | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader()); | |
this.qNamesToDeclaredClasses.put(next, declaredClass); | |
}catch(Exception e){ | |
} | |
} | |
if(nextElement.getJavaType().isEnum()) { | |
if(!(helper.getClassLoader() instanceof DynamicClassLoader)) { | |
// Only generate enum wrappers in non-dynamic case. | |
Class generatedClass = addEnumerationWrapperAndDescriptor(type, nextElement.getJavaType().getRawName(), nextElement, nextClassName, attributeTypeName); | |
this.qNamesToGeneratedClasses.put(next, generatedClass); | |
if(nextElement.getTypeMappingInfo() != null) { | |
typeMappingInfoToGeneratedClasses.put(nextElement.getTypeMappingInfo(), generatedClass); | |
} | |
try{ | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader()); | |
this.qNamesToDeclaredClasses.put(next, declaredClass); | |
}catch(Exception ex) { | |
} | |
} | |
} | |
continue; | |
} | |
Class generatedClass = generateWrapperClassAndDescriptor(type, next, nextElement, nextClassName, attributeTypeName); | |
this.qNamesToGeneratedClasses.put(next, generatedClass); | |
if(type != null && type.isEnumerationType() && nextElement.isXmlRootElement()) { | |
this.classToGeneratedClasses.put(type.getJavaClassName(), generatedClass); | |
} | |
try{ | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader()); | |
this.qNamesToDeclaredClasses.put(next, declaredClass); | |
}catch(Exception e){ | |
} | |
}else if(type != null && !type.isTransient()){ | |
if(next.getNamespaceURI() == null || next.getNamespaceURI().equals("")) { | |
if(type.getDescriptor().getDefaultRootElement() == null){ | |
type.getDescriptor().setDefaultRootElement(next.getLocalPart()); | |
}else{ | |
type.getDescriptor().addRootElement(next.getLocalPart()); | |
} | |
} else { | |
XMLDescriptor descriptor = type.getDescriptor(); | |
String uri = next.getNamespaceURI(); | |
String prefix = getPrefixForNamespace(uri, descriptor.getNamespaceResolver(),null); | |
if(type.getDescriptor().getDefaultRootElement() == null){ | |
descriptor.setDefaultRootElement(getQualifiedString(prefix, next.getLocalPart())); | |
}else{ | |
descriptor.addRootElement(getQualifiedString(prefix, next.getLocalPart())); | |
} | |
} | |
} | |
} | |
} | |
private Class addByteArrayWrapperAndDescriptor(TypeInfo type , String javaClassName, ElementDeclaration nextElement, String nextClassName, String attributeTypeName){ | |
Class generatedClass = classToGeneratedClasses.get(javaClassName); | |
if(generatedClass == null){ | |
generatedClass = generateWrapperClassAndDescriptor(type, null, nextElement, nextClassName, attributeTypeName); | |
classToGeneratedClasses.put(javaClassName, generatedClass); | |
} | |
return generatedClass; | |
} | |
private Class addEnumerationWrapperAndDescriptor(TypeInfo type, String javaClassName, ElementDeclaration nextElement, String nextClassName, String attributeTypeName) { | |
Class generatedClass = classToGeneratedClasses.get(javaClassName); | |
if(generatedClass == null){ | |
generatedClass = generateWrapperClassAndDescriptor(type, nextElement.getElementName(), nextElement, nextClassName, attributeTypeName); | |
classToGeneratedClasses.put(javaClassName, generatedClass); | |
} | |
return generatedClass; | |
} | |
private Class generateWrapperClassAndDescriptor(TypeInfo type, QName next, ElementDeclaration nextElement, String nextClassName, String attributeTypeName){ | |
String namespaceUri = null; | |
if(next!= null){ | |
//generate a class/descriptor for this element | |
namespaceUri = next.getNamespaceURI(); | |
if (namespaceUri == null || namespaceUri.equals(XMLProcessor.DEFAULT)) { | |
namespaceUri = ""; | |
} | |
} | |
TypeMappingInfo tmi = nextElement.getTypeMappingInfo(); | |
Class generatedClass = null; | |
JaxbClassLoader loader = getJaxbClassLoader(); | |
if(tmi != null){ | |
generatedClass = CompilerHelper.getExisitingGeneratedClass(tmi, typeMappingInfoToGeneratedClasses, typeMappingInfoToAdapterClasses, helper.getClassLoader()); | |
if(generatedClass == null){ | |
generatedClass = this.generateWrapperClass(loader.nextAvailableGeneratedClassName(), attributeTypeName, nextElement.isList(), next); | |
} | |
typeMappingInfoToGeneratedClasses.put(tmi, generatedClass); | |
}else{ | |
generatedClass = this.generateWrapperClass(loader.nextAvailableGeneratedClassName(), attributeTypeName, nextElement.isList(), next); | |
} | |
this.qNamesToGeneratedClasses.put(next, generatedClass); | |
try{ | |
Class declaredClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader()); | |
this.qNamesToDeclaredClasses.put(next, declaredClass); | |
}catch(Exception e){ | |
} | |
XMLDescriptor desc = (XMLDescriptor)project.getDescriptor(generatedClass); | |
if(desc == null){ | |
desc = new XMLDescriptor(); | |
desc.setJavaClass(generatedClass); | |
if(nextElement.isList()){ | |
XMLCompositeDirectCollectionMapping mapping = new XMLCompositeDirectCollectionMapping(); | |
mapping.setAttributeName("value"); | |
mapping.setXPath("text()"); | |
mapping.setUsesSingleNode(true); | |
mapping.setReuseContainer(true); | |
if(type != null && type.isEnumerationType()){ | |
mapping.setValueConverter(buildJAXBEnumTypeConverter(mapping, (EnumTypeInfo)type)); | |
}else{ | |
try{ | |
Class fieldElementClass = PrivilegedAccessHelper.getClassForName(nextClassName, false, helper.getClassLoader()); | |
mapping.setFieldElementClass(fieldElementClass); | |
}catch(ClassNotFoundException e){ | |
} | |
} | |
if(nextClassName.equals("[B") || nextClassName.equals("[Ljava.lang.Byte;")) { | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
} | |
else if(nextClassName.equals("javax.xml.namespace.QName")){ | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.QNAME_QNAME); | |
} | |
desc.addMapping(mapping); | |
} else{ | |
if(nextElement.getJavaTypeName().equals(OBJECT_CLASS_NAME)){ | |
XMLCompositeObjectMapping mapping = new XMLCompositeObjectMapping(); | |
mapping.setAttributeName("value"); | |
mapping.setSetMethodName("setValue"); | |
mapping.setGetMethodName("getValue"); | |
mapping.setKeepAsElementPolicy(UnmarshalKeepAsElementPolicy.KEEP_UNKNOWN_AS_ELEMENT); | |
mapping.setXPath("."); | |
((XMLField)mapping.getField()).setIsTypedTextField(true); | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.ANY_TYPE_QNAME); | |
desc.addMapping(mapping); | |
}else if(isBinaryData(nextElement.getJavaType())){ | |
XMLBinaryDataMapping mapping = new XMLBinaryDataMapping(); | |
mapping.setAttributeName("value"); | |
mapping.setXPath("."); | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
mapping.setSetMethodName("setValue"); | |
mapping.setGetMethodName("getValue"); | |
Class attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(attributeTypeName, getClass().getClassLoader()); | |
mapping.setAttributeClassification(attributeClassification); | |
mapping.setShouldInlineBinaryData(false); | |
if(nextElement.getTypeMappingInfo() != null) { | |
mapping.setSwaRef(nextElement.isXmlAttachmentRef()); | |
mapping.setMimeType(nextElement.getXmlMimeType()); | |
} | |
desc.addMapping(mapping); | |
}else{ | |
XMLDirectMapping mapping = new XMLDirectMapping(); | |
mapping.setNullValueMarshalled(true); | |
mapping.setAttributeName("value"); | |
mapping.setXPath("text()"); | |
mapping.setSetMethodName("setValue"); | |
mapping.setGetMethodName("getValue"); | |
if(nextElement.getDefaultValue() != null) { | |
mapping.setNullValue(nextElement.getDefaultValue()); | |
mapping.getNullPolicy().setNullRepresentedByXsiNil(true); | |
} | |
if(helper.isBuiltInJavaType(nextElement.getJavaType())){ | |
Class attributeClassification = null; | |
if(nextElement.getJavaType().isPrimitive()) { | |
attributeClassification = XMLConversionManager.getDefaultManager().convertClassNameToClass(attributeTypeName); | |
} else { | |
attributeClassification = org.eclipse.persistence.internal.helper.Helper.getClassFromClasseName(attributeTypeName, getClass().getClassLoader()); | |
} | |
mapping.setAttributeClassification(attributeClassification); | |
} | |
IsSetNullPolicy nullPolicy = new IsSetNullPolicy("isSetValue", false, true, XMLNullRepresentationType.ABSENT_NODE); | |
//nullPolicy.setNullRepresentedByEmptyNode(true); | |
mapping.setNullPolicy(nullPolicy); | |
if(type != null && type.isEnumerationType()){ | |
mapping.setConverter(buildJAXBEnumTypeConverter(mapping, (EnumTypeInfo)type)); | |
} | |
if(nextClassName.equals("[B") || nextClassName.equals("[Ljava.lang.Byte;")) { | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.BASE_64_BINARY_QNAME); | |
} | |
else if(nextClassName.equals("javax.xml.namespace.QName")){ | |
((XMLField)mapping.getField()).setSchemaType(XMLConstants.QNAME_QNAME); | |
} | |
if (nextElement.getJavaTypeAdapterClass() != null) { | |
mapping.setConverter(new XMLJavaTypeConverter(nextElement.getJavaTypeAdapterClass())); | |
} | |
desc.addMapping(mapping); | |
} | |
} | |
if(next != null){ | |
NamespaceInfo info = getNamespaceInfoForURI(namespaceUri); | |
if(info != null) { | |
NamespaceResolver resolver = info.getNamespaceResolverForDescriptor(); | |
String prefix = null; | |
if(namespaceUri != XMLConstants.EMPTY_STRING){ | |
prefix = resolver.resolveNamespaceURI(namespaceUri); | |
if(prefix == null){ | |
prefix = getPrefixForNamespace(namespaceUri, resolver, null); | |
} | |
} | |
desc.setNamespaceResolver(resolver); | |
if(nextElement.isXmlRootElement()) { | |
desc.setDefaultRootElement(getQualifiedString(prefix, next.getLocalPart())); | |
} else { | |
desc.setDefaultRootElement(""); | |
desc.addRootElement(getQualifiedString(prefix, next.getLocalPart())); | |
} | |
} else { | |
if(namespaceUri.equals("")) { | |
desc.setDefaultRootElement(next.getLocalPart()); | |
} else { | |
NamespaceResolver resolver = new NamespaceResolver(); | |
String prefix = getPrefixForNamespace(namespaceUri, resolver, null); | |
desc.setNamespaceResolver(resolver); | |
if(nextElement.isXmlRootElement()) { | |
desc.setDefaultRootElement(getQualifiedString(prefix, next.getLocalPart())); | |
} else { | |
desc.setDefaultRootElement(""); | |
desc.addRootElement(getQualifiedString(prefix, next.getLocalPart())); | |
} | |
} | |
} | |
} | |
project.addDescriptor(desc); | |
} | |
return generatedClass; | |
} | |
private String getQualifiedString(String prefix, String localPart){ | |
if(prefix == null){ | |
return localPart; | |
} | |
return prefix + XMLConstants.COLON + localPart; | |
} | |
private NamespaceInfo getNamespaceInfoForURI(String namespaceUri) { | |
Iterator<PackageInfo> namespaces = this.packageToPackageInfoMappings.values().iterator(); | |
while(namespaces.hasNext()) { | |
NamespaceInfo next = namespaces.next().getNamespaceInfo(); | |
if(next.getNamespace().equals(namespaceUri)) { | |
return next; | |
} | |
} | |
return null; | |
} | |
@SuppressWarnings("unused") | |
private String getPackageNameForURI(String namespaceUri) { | |
for(String next:this.packageToPackageInfoMappings.keySet()) { | |
if(packageToPackageInfoMappings.get(next).getNamespace().equals(namespaceUri)) { | |
return next; | |
} | |
} | |
return null; | |
} | |
public Class generateWrapperClass(String className, String attributeType, boolean isList, QName theQName) { | |
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); | |
String sig = null; | |
cw.visit(Opcodes.V1_5, Opcodes.ACC_PUBLIC, className.replace(".", "/"), sig, Type.getType(WrappedValue.class).getInternalName(), null); | |
String fieldType = null; | |
if(isList){ | |
fieldType ="Ljava/util/List;"; | |
}else{ | |
fieldType = attributeType.replace(".", "/"); | |
if(!(fieldType.startsWith("["))) { | |
fieldType = "L" + fieldType + ";"; | |
} | |
} | |
if(theQName == null){ | |
theQName = RESERVED_QNAME; | |
} | |
MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); | |
mv.visitVarInsn(Opcodes.ALOAD, 0); | |
mv.visitTypeInsn(Opcodes.NEW, "javax/xml/namespace/QName"); | |
mv.visitInsn(Opcodes.DUP); | |
mv.visitLdcInsn(theQName.getNamespaceURI()); | |
mv.visitLdcInsn(theQName.getLocalPart()); | |
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "javax/xml/namespace/QName", "<init>", "(Ljava/lang/String;Ljava/lang/String;)V"); | |
mv.visitLdcInsn(Type.getType(fieldType)); | |
mv.visitInsn(Opcodes.ACONST_NULL); | |
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/eclipse/persistence/internal/jaxb/WrappedValue", "<init>", "(Ljavax/xml/namespace/QName;Ljava/lang/Class;Ljava/lang/Object;)V"); | |
mv.visitInsn(Opcodes.RETURN); | |
mv.visitMaxs(5, 1); | |
mv.visitEnd(); | |
cw.visitEnd(); | |
byte[] classBytes = cw.toByteArray(); | |
//byte[] classBytes = new byte[]{}; | |
Class generatedClass = getJaxbClassLoader().generateClass(className, classBytes); | |
return generatedClass; | |
} | |
public HashMap<QName, Class> getQNamesToGeneratedClasses() { | |
return qNamesToGeneratedClasses; | |
} | |
public HashMap<String, Class> getClassToGeneratedClasses() { | |
return classToGeneratedClasses; | |
} | |
public HashMap<QName, Class> getQNamesToDeclaredClasses() { | |
return qNamesToDeclaredClasses; | |
} | |
private Map<MapEntryGeneratedKey, Class> getGeneratedMapEntryClasses() { | |
if(generatedMapEntryClasses == null){ | |
generatedMapEntryClasses = new HashMap<MapEntryGeneratedKey, Class>(); | |
} | |
return generatedMapEntryClasses; | |
} | |
private class MapEntryGeneratedKey { | |
@SuppressWarnings("unused") | |
String keyClassName; | |
@SuppressWarnings("unused") | |
String valueClassName; | |
public MapEntryGeneratedKey(String keyClass, String valueClass){ | |
keyClassName = keyClass; | |
valueClassName = valueClass; | |
} | |
} | |
private AbstractNullPolicy getWrapperNullPolicyFromProperty(Property property) { | |
NullPolicy nullPolicy = null; | |
if (property.isSetXmlElementWrapper()) { | |
nullPolicy = new NullPolicy(); | |
nullPolicy.setNullRepresentedByEmptyNode(false); | |
nullPolicy.setSetPerformedForAbsentNode(false); | |
if (property.getXmlElementWrapper().isNillable()) { | |
nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.XSI_NIL); | |
nullPolicy.setNullRepresentedByXsiNil(true); | |
} else { | |
nullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.ABSENT_NODE); | |
nullPolicy.setNullRepresentedByXsiNil(false); | |
} | |
} | |
return nullPolicy; | |
} | |
/** | |
* Convenience method which returns an AbstractNullPolicy built from an XmlAbstractNullPolicy. | |
* | |
* @param property | |
* @param nsr if 'NullRepresentedByXsiNil' is true, this is the resolver | |
* that we will add the schema instance prefix/uri pair to | |
* @return | |
* @see org.eclipse.persistence.oxm.mappings.nullpolicy.AbstractNullPolicy | |
* @see org.eclipse.persistence.jaxb.xmlmodel.XmlAbstractNullPolicy | |
*/ | |
private AbstractNullPolicy getNullPolicyFromProperty(Property property, NamespaceResolver nsr) { | |
AbstractNullPolicy absNullPolicy = null; | |
XmlAbstractNullPolicy xmlAbsNullPolicy = property.getNullPolicy(); | |
// policy is assumed to be one of XmlNullPolicy or XmlIsSetNullPolicy | |
if (xmlAbsNullPolicy instanceof XmlNullPolicy) { | |
XmlNullPolicy xmlNullPolicy = (XmlNullPolicy) xmlAbsNullPolicy; | |
NullPolicy nullPolicy = new NullPolicy(); | |
nullPolicy.setSetPerformedForAbsentNode(xmlNullPolicy.isIsSetPerformedForAbsentNode()); | |
absNullPolicy = nullPolicy; | |
} else { | |
XmlIsSetNullPolicy xmlIsSetNullPolicy = (XmlIsSetNullPolicy) xmlAbsNullPolicy; | |
IsSetNullPolicy isSetNullPolicy = new IsSetNullPolicy(); | |
isSetNullPolicy.setIsSetMethodName(xmlIsSetNullPolicy.getIsSetMethodName()); | |
// handle isSetParams | |
ArrayList<Object> parameters = new ArrayList<Object>(); | |
ArrayList<Class> parameterTypes = new ArrayList<Class>(); | |
List<XmlIsSetNullPolicy.IsSetParameter> params = xmlIsSetNullPolicy.getIsSetParameter(); | |
for (XmlIsSetNullPolicy.IsSetParameter param : params) { | |
String valueStr = param.getValue(); | |
String typeStr = param.getType(); | |
// create a conversion manager instance with the helper's loader | |
XMLConversionManager mgr = new XMLConversionManager(); | |
mgr.setLoader(helper.getClassLoader()); | |
// handle parameter type | |
Class typeClass = mgr.convertClassNameToClass(typeStr); | |
// handle parameter value | |
Object parameterValue = mgr.convertObject(valueStr, typeClass); | |
parameters.add(parameterValue); | |
parameterTypes.add(typeClass); | |
} | |
isSetNullPolicy.setIsSetParameters(parameters.toArray()); | |
isSetNullPolicy.setIsSetParameterTypes(parameterTypes.toArray(new Class[parameterTypes.size()])); | |
absNullPolicy = isSetNullPolicy; | |
} | |
// handle commmon settings | |
absNullPolicy.setMarshalNullRepresentation(XMLNullRepresentationType.valueOf(xmlAbsNullPolicy.getNullRepresentationForXml().name())); | |
absNullPolicy.setNullRepresentedByEmptyNode(xmlAbsNullPolicy.isEmptyNodeRepresentsNull()); | |
boolean xsiRepresentsNull = xmlAbsNullPolicy.isXsiNilRepresentsNull(); | |
if (xsiRepresentsNull) { | |
absNullPolicy.setNullRepresentedByXsiNil(true); | |
} | |
return absNullPolicy; | |
} | |
/** | |
* Return the base component type for a class. For example, the base | |
* component type for Integer, Integer[], and Integer[][] are all Integer. | |
*/ | |
private JavaClass getBaseComponentType(JavaClass javaClass) { | |
JavaClass componentType = javaClass.getComponentType(); | |
if(null == componentType) { | |
return javaClass; | |
} | |
if(!componentType.isArray()) { | |
return componentType; | |
} | |
return getBaseComponentType(componentType); | |
} | |
public JaxbClassLoader getJaxbClassLoader() { | |
if (helper.getClassLoader() instanceof DynamicClassLoader) { | |
return (JaxbClassLoader) helper.getClassLoader().getParent(); | |
} else { | |
return (JaxbClassLoader) helper.getClassLoader(); | |
} | |
} | |
private boolean isBinaryData(JavaClass type){ | |
return areEquals(type, ClassConstants.APBYTE) ||areEquals(type, "javax.activation.DataHandler") || areEquals(type, "java.awt.Image") || areEquals(type, "javax.xml.transform.Source") || areEquals(type, "javax.mail.internet.MimeMultipart"); | |
} | |
/** | |
* <p>An InstantiationPolicy that does not construct any objects (and therefore | |
* will not throw validation errors caused by a lack of a no-arg constructor).</p> | |
* | |
* <p>This is used by @XmlLocation, where we want to have a real mapping created | |
* (so we can later set its value through the mapping), but where we will never | |
* instantiate a Locator from XML (the Locator will be built internally during parsing).</p> | |
* | |
* @see org.eclipse.persistence.internal.descriptors.InstantiationPolicy | |
* @see org.xml.sax.Locator | |
*/ | |
private class NullInstantiationPolicy extends InstantiationPolicy { | |
/** | |
* Returns a new instance of this InstantiationPolicy's Descriptor's class. | |
* | |
* In this case, do nothing and return null. | |
*/ | |
@Override | |
public Object buildNewInstance() throws DescriptorException { | |
return null; | |
} | |
} | |
private void initializeXMLContainerMapping(XMLContainerMapping xmlContainerMapping) { | |
xmlContainerMapping.setReuseContainer(true); | |
xmlContainerMapping.setDefaultEmptyContainer(false); | |
} | |
private JavaClass containerClassImpl(JavaClass collectionType) { | |
if (areEquals(collectionType, List.class) || areEquals(collectionType, Collection.class) || collectionType.isArray()) { | |
return jotArrayList; | |
} else if (areEquals(collectionType, Set.class)) { | |
return jotHashSet; | |
} else if (areEquals(collectionType, Deque.class) || areEquals(collectionType, Queue.class)) { | |
return jotLinkedList; | |
} else if (areEquals(collectionType, NavigableSet.class) || areEquals(collectionType, SortedSet.class)) { | |
return jotTreeSet; | |
} else { | |
return collectionType; | |
} | |
} | |
} |