| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0, |
| * or the Eclipse Distribution License v. 1.0 which is available at |
| * http://www.eclipse.org/org/documents/edl-v10.php. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause |
| */ |
| |
| // Contributors: |
| // Oracle - initial API and implementation from Oracle TopLink |
| package org.eclipse.persistence.jaxb.compiler; |
| |
| import java.awt.Image; |
| import java.beans.Introspector; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.lang.reflect.ParameterizedType; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import jakarta.validation.constraints.DecimalMax; |
| import jakarta.validation.constraints.DecimalMin; |
| import jakarta.validation.constraints.Digits; |
| import jakarta.validation.constraints.Max; |
| import jakarta.validation.constraints.Min; |
| import jakarta.validation.constraints.NotNull; |
| import jakarta.validation.constraints.Pattern; |
| import jakarta.validation.constraints.Size; |
| import jakarta.xml.bind.Marshaller; |
| import jakarta.xml.bind.Unmarshaller; |
| import jakarta.xml.bind.annotation.XmlAccessorOrder; |
| import jakarta.xml.bind.annotation.XmlAccessorType; |
| import jakarta.xml.bind.annotation.XmlAnyAttribute; |
| import jakarta.xml.bind.annotation.XmlAnyElement; |
| import jakarta.xml.bind.annotation.XmlAttachmentRef; |
| import jakarta.xml.bind.annotation.XmlAttribute; |
| import jakarta.xml.bind.annotation.XmlElement; |
| import jakarta.xml.bind.annotation.XmlElementDecl; |
| import jakarta.xml.bind.annotation.XmlElementRef; |
| import jakarta.xml.bind.annotation.XmlElementRefs; |
| import jakarta.xml.bind.annotation.XmlElementWrapper; |
| import jakarta.xml.bind.annotation.XmlElements; |
| import jakarta.xml.bind.annotation.XmlEnum; |
| import jakarta.xml.bind.annotation.XmlEnumValue; |
| import jakarta.xml.bind.annotation.XmlID; |
| import jakarta.xml.bind.annotation.XmlIDREF; |
| import jakarta.xml.bind.annotation.XmlInlineBinaryData; |
| import jakarta.xml.bind.annotation.XmlList; |
| import jakarta.xml.bind.annotation.XmlMimeType; |
| import jakarta.xml.bind.annotation.XmlMixed; |
| import jakarta.xml.bind.annotation.XmlNs; |
| import jakarta.xml.bind.annotation.XmlNsForm; |
| import jakarta.xml.bind.annotation.XmlRegistry; |
| import jakarta.xml.bind.annotation.XmlRootElement; |
| import jakarta.xml.bind.annotation.XmlSchema; |
| import jakarta.xml.bind.annotation.XmlSchemaType; |
| import jakarta.xml.bind.annotation.XmlSchemaTypes; |
| import jakarta.xml.bind.annotation.XmlTransient; |
| import jakarta.xml.bind.annotation.XmlType; |
| import jakarta.xml.bind.annotation.XmlType.DEFAULT; |
| import jakarta.xml.bind.annotation.XmlValue; |
| import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter; |
| import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapters; |
| import javax.xml.namespace.QName; |
| import javax.xml.transform.Source; |
| |
| import org.eclipse.persistence.exceptions.ConversionException; |
| import org.eclipse.persistence.exceptions.JAXBException; |
| import org.eclipse.persistence.internal.core.helper.CoreClassConstants; |
| import org.eclipse.persistence.internal.helper.ClassConstants; |
| import org.eclipse.persistence.internal.helper.ConversionManager; |
| import org.eclipse.persistence.internal.jaxb.AccessorFactoryWrapper; |
| import org.eclipse.persistence.internal.jaxb.JaxbClassLoader; |
| import org.eclipse.persistence.internal.jaxb.many.ArrayValue; |
| import org.eclipse.persistence.internal.jaxb.many.CollectionValue; |
| import org.eclipse.persistence.internal.jaxb.many.ManyValue; |
| import org.eclipse.persistence.internal.jaxb.many.MultiDimensionalArrayValue; |
| import org.eclipse.persistence.internal.jaxb.many.MultiDimensionalCollectionValue; |
| import org.eclipse.persistence.internal.libraries.asm.AnnotationVisitor; |
| import org.eclipse.persistence.internal.libraries.asm.ClassWriter; |
| import org.eclipse.persistence.internal.libraries.asm.EclipseLinkASMClassWriter; |
| import org.eclipse.persistence.internal.libraries.asm.FieldVisitor; |
| import org.eclipse.persistence.internal.libraries.asm.Label; |
| 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.Constants; |
| import org.eclipse.persistence.internal.oxm.Namespace; |
| import org.eclipse.persistence.internal.oxm.XMLConversionManager; |
| import org.eclipse.persistence.internal.oxm.XPathFragment; |
| import org.eclipse.persistence.internal.oxm.mappings.Field; |
| import org.eclipse.persistence.internal.security.PrivilegedAccessHelper; |
| import org.eclipse.persistence.jaxb.MOXySystemProperties; |
| import org.eclipse.persistence.jaxb.TypeMappingInfo; |
| import org.eclipse.persistence.jaxb.compiler.facets.DecimalMaxFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.DecimalMinFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.DigitsFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.MaxFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.MinFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.PatternFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.PatternListFacet; |
| import org.eclipse.persistence.jaxb.compiler.facets.SizeFacet; |
| import org.eclipse.persistence.jaxb.javamodel.AnnotationProxy; |
| import org.eclipse.persistence.jaxb.javamodel.Helper; |
| import org.eclipse.persistence.jaxb.javamodel.JavaAnnotation; |
| import org.eclipse.persistence.jaxb.javamodel.JavaClass; |
| import org.eclipse.persistence.jaxb.javamodel.JavaConstructor; |
| import org.eclipse.persistence.jaxb.javamodel.JavaField; |
| import org.eclipse.persistence.jaxb.javamodel.JavaHasAnnotations; |
| import org.eclipse.persistence.jaxb.javamodel.JavaMethod; |
| import org.eclipse.persistence.jaxb.javamodel.JavaPackage; |
| import org.eclipse.persistence.jaxb.javamodel.reflection.JavaFieldImpl; |
| import org.eclipse.persistence.jaxb.xmlmodel.XmlAccessOrder; |
| import org.eclipse.persistence.jaxb.xmlmodel.XmlAccessType; |
| import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation; |
| import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlReadTransformer; |
| import org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlWriteTransformer; |
| import org.eclipse.persistence.mappings.transformers.AttributeTransformer; |
| import org.eclipse.persistence.mappings.transformers.FieldTransformer; |
| import org.eclipse.persistence.oxm.NamespaceResolver; |
| import org.eclipse.persistence.oxm.XMLField; |
| import org.eclipse.persistence.oxm.XMLNameTransformer; |
| import org.eclipse.persistence.oxm.annotations.XmlAccessMethods; |
| import org.eclipse.persistence.oxm.annotations.XmlCDATA; |
| import org.eclipse.persistence.oxm.annotations.XmlClassExtractor; |
| import org.eclipse.persistence.oxm.annotations.XmlCustomizer; |
| import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode; |
| import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue; |
| import org.eclipse.persistence.oxm.annotations.XmlElementNillable; |
| import org.eclipse.persistence.oxm.annotations.XmlElementsJoinNodes; |
| import org.eclipse.persistence.oxm.annotations.XmlIDExtension; |
| import org.eclipse.persistence.oxm.annotations.XmlInverseReference; |
| import org.eclipse.persistence.oxm.annotations.XmlIsSetNullPolicy; |
| import org.eclipse.persistence.oxm.annotations.XmlJoinNode; |
| import org.eclipse.persistence.oxm.annotations.XmlJoinNodes; |
| import org.eclipse.persistence.oxm.annotations.XmlKey; |
| import org.eclipse.persistence.oxm.annotations.XmlLocation; |
| import org.eclipse.persistence.oxm.annotations.XmlNameTransformer; |
| import org.eclipse.persistence.oxm.annotations.XmlNamedAttributeNode; |
| import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraph; |
| import org.eclipse.persistence.oxm.annotations.XmlNamedObjectGraphs; |
| import org.eclipse.persistence.oxm.annotations.XmlNamedSubgraph; |
| import org.eclipse.persistence.oxm.annotations.XmlNullPolicy; |
| import org.eclipse.persistence.oxm.annotations.XmlParameter; |
| import org.eclipse.persistence.oxm.annotations.XmlPath; |
| import org.eclipse.persistence.oxm.annotations.XmlPaths; |
| import org.eclipse.persistence.oxm.annotations.XmlProperties; |
| import org.eclipse.persistence.oxm.annotations.XmlProperty; |
| import org.eclipse.persistence.oxm.annotations.XmlReadOnly; |
| import org.eclipse.persistence.oxm.annotations.XmlValueExtension; |
| import org.eclipse.persistence.oxm.annotations.XmlVariableNode; |
| import org.eclipse.persistence.oxm.annotations.XmlVirtualAccessMethods; |
| import org.eclipse.persistence.oxm.annotations.XmlWriteOnly; |
| import org.eclipse.persistence.oxm.annotations.XmlWriteTransformers; |
| |
| /** |
| * INTERNAL: |
| * <p> |
| * <b>Purpose:</b>To perform some initial processing of Java classes and JAXB |
| * 2.0 Annotations and generate meta data that can be used by the Mappings |
| * Generator and Schema Generator |
| * <p> |
| * <b>Responsibilities:</b> |
| * <ul> |
| * <li>Generate a map of TypeInfo objects, keyed on class name</li> |
| * <li>Generate a map of user defined schema types</li> |
| * <li>Identify any class-based JAXB 2.0 callback methods, and create |
| * MarshalCallback and UnmarshalCallback objects to wrap them.</li> |
| * <li>Centralize processing which is common to both Schema Generation and |
| * Mapping Generation tasks</li> |
| * </ul> |
| * <p> |
| * This class does the initial processing of the JAXB 2.0 Generation. It |
| * generates meta data that can be used by the later Schema Generation and |
| * Mapping Generation steps. |
| * |
| * @see org.eclipse.persistence.jaxb.compiler.Generator |
| * @author mmacivor |
| * @since Oracle TopLink 11.1.1.0.0 |
| */ |
| public final class AnnotationsProcessor { |
| |
| static final String ARRAY_PACKAGE_NAME = "jaxb.dev.java.net.array"; |
| static final String JAVAX_ACTIVATION_DATAHANDLER = "jakarta.activation.DataHandler"; |
| static final String JAVAX_MAIL_INTERNET_MIMEMULTIPART = "jakarta.mail.internet.MimeMultipart"; |
| private static final String JAVAX_XML_BIND_JAXBELEMENT = "jakarta.xml.bind.JAXBElement"; |
| private static final String JAVAX_XML_BIND_ANNOTATION = "jakarta.xml.bind.annotation"; |
| private static final String OXM_ANNOTATIONS = "org.eclipse.persistence.oxm.annotations"; |
| private static final String TYPE_METHOD_NAME = "type"; |
| private static final String VALUE_METHOD_NAME = "value"; |
| private static final String ARRAY_NAMESPACE = "http://jaxb.dev.java.net/array"; |
| private static final String ARRAY_CLASS_NAME_SUFFIX = "Array"; |
| private static final String JAXB_DEV = "jaxb.dev.java.net"; |
| private static final String ORG_W3C_DOM = "org.w3c.dom"; |
| private static final String CREATE = "create"; |
| private static final String ELEMENT_DECL_GLOBAL = "jakarta.xml.bind.annotation.XmlElementDecl.GLOBAL"; |
| private static final String ELEMENT_DECL_DEFAULT = "\u0000"; |
| private static final String EMPTY_STRING = ""; |
| private static final String JAVA_UTIL_LIST = "java.util.List"; |
| private static final String JAVA_LANG_OBJECT = "java.lang.Object"; |
| private static final String SLASH = "/"; |
| private static final String SEMI_COLON = ";"; |
| private static final String L = "L"; |
| private static final String ITEM = "item"; |
| private static final String IS_STR = "is"; |
| private static final String GET_STR = "get"; |
| private static final String SET_STR = "set"; |
| private static final Character DOT_CHR = '.'; |
| private static final Character DOLLAR_SIGN_CHR = '$'; |
| private static final Character SLASH_CHR = '/'; |
| |
| private List<JavaClass> typeInfoClasses; |
| private Map<String, PackageInfo> packageToPackageInfoMappings; |
| private HashMap<String, XmlNillableInfo> packageToXmlNillableInfoMappings; |
| private Map<String, MarshalCallback> marshalCallbacks; |
| private Map<String, QName> userDefinedSchemaTypes; |
| private Map<String, TypeInfo> typeInfos; |
| private List<QName> typeQNames; |
| private Map<String, UnmarshalCallback> unmarshalCallbacks; |
| private Map<String, Map<QName, ElementDeclaration>> elementDeclarations; |
| private Map<String, ElementDeclaration> xmlRootElements; |
| private List<ElementDeclaration> localElements; |
| private Map<String, JavaMethod> factoryMethods; |
| private Map<String, org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry> xmlRegistries; |
| private List<String> objectFactoryClassNames; |
| private List<JavaClass> classesToProcessPropertyTypes; |
| |
| private Map<String, Class> arrayClassesToGeneratedClasses; |
| private Map<Class, JavaClass> generatedClassesToArrayClasses; |
| private Map<java.lang.reflect.Type, Class> collectionClassesToGeneratedClasses; |
| private Map<Class, java.lang.reflect.Type> generatedClassesToCollectionClasses; |
| private Map<JavaClass, List<TypeMappingInfo>> javaClassToTypeMappingInfos; |
| private Map<TypeMappingInfo, Class> typeMappingInfosToGeneratedClasses; |
| private Map<TypeMappingInfo, Class> typeMappingInfoToAdapterClasses; |
| private Map<TypeMappingInfo, QName> typeMappingInfosToSchemaTypes; |
| |
| private Helper helper; |
| private String defaultTargetNamespace; |
| |
| private JAXBMetadataLogger logger; |
| |
| private boolean isDefaultNamespaceAllowed; |
| private boolean xmlAccessorFactorySupport; |
| |
| private boolean hasSwaRef; |
| |
| private List<String> referencedByTransformer; |
| private boolean hasXmlBindings = false; |
| private boolean facets; |
| |
| public AnnotationsProcessor(Helper helper) { |
| this.helper = helper; |
| this.facets = helper.isFacets(); |
| isDefaultNamespaceAllowed = true; |
| hasSwaRef = false; |
| } |
| |
| /** |
| * This event is called when annotation processing is completed, |
| * and provides a chance to deference anything that is no longer |
| * needed (to reduce the memory footprint of this object). |
| */ |
| void postInitialize() { |
| typeInfoClasses = null; |
| packageToPackageInfoMappings = null; |
| typeInfos = null; |
| typeQNames = null; |
| elementDeclarations = null; |
| xmlRootElements = null; |
| localElements = null; |
| factoryMethods = null; |
| xmlRegistries = null; |
| objectFactoryClassNames = null; |
| classesToProcessPropertyTypes = null; |
| javaClassToTypeMappingInfos = null; |
| typeMappingInfosToGeneratedClasses = null; |
| typeMappingInfoToAdapterClasses = null; |
| helper = null; |
| logger = null; |
| referencedByTransformer = null; |
| } |
| |
| /** |
| * Generate TypeInfo instances for a given array of JavaClasses. |
| * |
| */ |
| void processClassesAndProperties(JavaClass[] classes, TypeMappingInfo[] typeMappingInfos) { |
| init(classes, typeMappingInfos); |
| preBuildTypeInfo(classes); |
| postBuildTypeInfo(classes); |
| processPropertyTypes(this.typeInfoClasses.toArray(new JavaClass[this.typeInfoClasses.size()])); |
| finalizeProperties(); |
| createElementsForTypeMappingInfo(); |
| checkForCallbackMethods(); |
| } |
| |
| public void createElementsForTypeMappingInfo() { |
| if (javaClassToTypeMappingInfos != null && !javaClassToTypeMappingInfos.isEmpty()) { |
| Set<JavaClass> classes = this.javaClassToTypeMappingInfos.keySet(); |
| for (JavaClass nextClass : classes) { |
| List<TypeMappingInfo> nextInfos = this.javaClassToTypeMappingInfos.get(nextClass); |
| for(TypeMappingInfo nextInfo:nextInfos) { |
| if (nextInfo != null) { |
| boolean xmlAttachmentRef = false; |
| String xmlMimeType = null; |
| java.lang.annotation.Annotation[] annotations = getAnnotations(nextInfo); |
| Class adapterClass = typeMappingInfoToAdapterClasses.get(nextInfo); |
| Class declJavaType = null; |
| if (adapterClass != null) { |
| declJavaType = CompilerHelper.getTypeFromAdapterClass(adapterClass); |
| } |
| if (annotations != null) { |
| for (Annotation nextAnnotation : annotations) { |
| if (nextAnnotation != null) { |
| if (nextAnnotation instanceof XmlMimeType) { |
| XmlMimeType javaAnnotation = (XmlMimeType) nextAnnotation; |
| xmlMimeType = javaAnnotation.value(); |
| } else if (nextAnnotation instanceof XmlAttachmentRef) { |
| xmlAttachmentRef = true; |
| if (!this.hasSwaRef) { |
| this.hasSwaRef = true; |
| } |
| } |
| } |
| } |
| } |
| |
| QName qname; |
| |
| String nextClassName = nextClass.getQualifiedName(); |
| |
| if (declJavaType != null) { |
| nextClassName = declJavaType.getCanonicalName(); |
| } |
| |
| if (typeMappingInfosToGeneratedClasses != null) { |
| Class generatedClass = typeMappingInfosToGeneratedClasses.get(nextInfo); |
| if (generatedClass != null) { |
| nextClassName = generatedClass.getCanonicalName(); |
| } |
| } |
| |
| TypeInfo nextTypeInfo = typeInfos.get(nextClassName); |
| if (nextTypeInfo != null) { |
| qname = new QName(nextTypeInfo.getClassNamespace(), nextTypeInfo.getSchemaTypeName()); |
| } else { |
| qname = getUserDefinedSchemaTypes().get(nextClassName); |
| if (qname == null) { |
| if (nextClassName.equals(ClassConstants.APBYTE.getName()) || nextClassName.equals(Image.class.getName()) || nextClassName.equals(Source.class.getName()) || nextClassName.equals("jakarta.activation.DataHandler")) { |
| if (xmlAttachmentRef) { |
| qname = Constants.SWA_REF_QNAME; |
| } else { |
| qname = Constants.BASE_64_BINARY_QNAME; |
| } |
| } else if (nextClassName.equals(ClassConstants.OBJECT.getName())) { |
| qname = Constants.ANY_TYPE_QNAME; |
| } else if (nextClassName.equals(ClassConstants.XML_GREGORIAN_CALENDAR.getName())) { |
| qname = Constants.ANY_SIMPLE_TYPE_QNAME; |
| } else { |
| Class theClass = helper.getClassForJavaClass(nextClass); |
| qname = XMLConversionManager.getDefaultJavaTypes().get(theClass); |
| } |
| } |
| } |
| |
| if (qname != null) { |
| typeMappingInfosToSchemaTypes.put(nextInfo, qname); |
| } |
| |
| if (nextInfo.getXmlTagName() != null) { |
| ElementDeclaration element = new ElementDeclaration(nextInfo.getXmlTagName(), nextClass, nextClass.getQualifiedName(), false); |
| element.setTypeMappingInfo(nextInfo); |
| element.setXmlMimeType(xmlMimeType); |
| element.setXmlAttachmentRef(xmlAttachmentRef); |
| element.setNillable(nextInfo.isNillable()); |
| |
| if (declJavaType != null) { |
| element.setJavaType(helper.getJavaClass(declJavaType)); |
| } |
| Class generatedClass = typeMappingInfosToGeneratedClasses.get(nextInfo); |
| if (generatedClass != null) { |
| element.setJavaType(helper.getJavaClass(generatedClass)); |
| } |
| if (nextInfo.getElementScope() == TypeMappingInfo.ElementScope.Global) { |
| ElementDeclaration currentElement = this.getGlobalElements().get(element.getElementName()); |
| if (currentElement == null) { |
| addGlobalElement(element.getElementName(), element); |
| } else { |
| // if(currentElement.getTypeMappingInfo() == null) { |
| // the global element that exists came from an annotation |
| |
| //} else { |
| this.localElements.add(element); |
| //} |
| } |
| } else { |
| this.localElements.add(element); |
| } |
| String rootNamespace = element.getElementName().getNamespaceURI(); |
| if (rootNamespace == null) { |
| rootNamespace = Constants.EMPTY_STRING; |
| } |
| if (rootNamespace.equals(Constants.EMPTY_STRING)) { |
| isDefaultNamespaceAllowed = false; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns an array of Annotations for a given TypeMappingInfo. This array |
| * will either be populated from the TypeMappingInfo's array of annotations, |
| * or based on an xml-element if present. The xml-element will take |
| * precedence over the annotation array; if there is an xml-element the |
| * Array of Annotations will be ignored. |
| * |
| */ |
| private java.lang.annotation.Annotation[] getAnnotations(TypeMappingInfo tmInfo) { |
| if (tmInfo.getXmlElement() != null) { |
| ClassLoader loader = helper.getClassLoader(); |
| // create a single ConversionManager for that will be shared by the |
| // proxy objects |
| ConversionManager cMgr = new ConversionManager(); |
| cMgr.setLoader(loader); |
| |
| // unmarshal the node into an XmlElement |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElement xElt = CompilerHelper.getXmlElement(tmInfo.getXmlElement(), loader); |
| List annotations = new ArrayList(); |
| // where applicable, a given dynamic proxy will contain a Map of |
| // method name/return value entries |
| Map<String, Object> components = null; |
| // handle @XmlElement: set 'type' method |
| if (!(xElt.getType().equals("jakarta.xml.bind.annotation.XmlElement.DEFAULT"))) { |
| components = new HashMap<String, Object>(); |
| components.put(TYPE_METHOD_NAME, xElt.getType()); |
| annotations.add(AnnotationProxy.getProxy(components, XmlElement.class, loader, cMgr)); |
| } |
| // handle @XmlList |
| if (xElt.isXmlList()) { |
| annotations.add(AnnotationProxy.getProxy(components, XmlList.class, loader, cMgr)); |
| } |
| // handle @XmlAttachmentRef |
| if (xElt.isXmlAttachmentRef()) { |
| annotations.add(AnnotationProxy.getProxy(components, XmlAttachmentRef.class, loader, cMgr)); |
| } |
| // handle @XmlMimeType: set 'value' method |
| if (xElt.getXmlMimeType() != null) { |
| components = new HashMap<String, Object>(); |
| components.put(VALUE_METHOD_NAME, xElt.getXmlMimeType()); |
| annotations.add(AnnotationProxy.getProxy(components, XmlMimeType.class, loader, cMgr)); |
| } |
| // handle @XmlJavaTypeAdapter: set 'type' and 'value' methods |
| if (xElt.getXmlJavaTypeAdapter() != null) { |
| components = new HashMap<String, Object>(); |
| components.put(TYPE_METHOD_NAME, xElt.getXmlJavaTypeAdapter().getType()); |
| components.put(VALUE_METHOD_NAME, xElt.getXmlJavaTypeAdapter().getValue()); |
| annotations.add(AnnotationProxy.getProxy(components, XmlJavaTypeAdapter.class, loader, cMgr)); |
| } |
| // return the newly created array of dynamic proxy objects |
| return (java.lang.annotation.Annotation[]) annotations.toArray(new java.lang.annotation.Annotation[annotations.size()]); |
| } |
| // no xml-element set on the info, (i.e. no xml overrides) so return the |
| // array of Annotation objects |
| return tmInfo.getAnnotations(); |
| } |
| |
| /** |
| * Initialize maps, lists, etc. Typically called prior to processing a set |
| * of classes via preBuildTypeInfo, postBuildTypeInfo, processJavaClasses. |
| */ |
| void init(JavaClass[] classes, TypeMappingInfo[] typeMappingInfos) { |
| typeInfoClasses = new ArrayList<JavaClass>(); |
| referencedByTransformer = new ArrayList<String>(); |
| typeInfos = new HashMap<String, TypeInfo>(); |
| typeQNames = new ArrayList<QName>(); |
| classesToProcessPropertyTypes = new ArrayList<JavaClass>(); |
| objectFactoryClassNames = new ArrayList<String>(); |
| userDefinedSchemaTypes = new HashMap<String, QName>(); |
| if (packageToPackageInfoMappings == null) { |
| packageToPackageInfoMappings = new HashMap<String, PackageInfo>(); |
| } |
| this.factoryMethods = new HashMap<String, JavaMethod>(); |
| this.xmlRegistries = new HashMap<String, org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry>(); |
| this.xmlRootElements = new HashMap<String, ElementDeclaration>(); |
| |
| arrayClassesToGeneratedClasses = new HashMap<String, Class>(); |
| collectionClassesToGeneratedClasses = new HashMap<java.lang.reflect.Type, Class>(); |
| generatedClassesToArrayClasses = new HashMap<Class, JavaClass>(); |
| generatedClassesToCollectionClasses = new HashMap<Class, java.lang.reflect.Type>(); |
| typeMappingInfosToGeneratedClasses = new HashMap<TypeMappingInfo, Class>(); |
| typeMappingInfosToSchemaTypes = new HashMap<TypeMappingInfo, QName>(); |
| elementDeclarations = new HashMap<String, Map<QName, ElementDeclaration>>(); |
| Map globalElements = new HashMap<QName, ElementDeclaration>(); |
| elementDeclarations.put(XmlElementDecl.GLOBAL.class.getName(), globalElements); |
| localElements = new ArrayList<ElementDeclaration>(); |
| |
| javaClassToTypeMappingInfos = new HashMap<JavaClass, List<TypeMappingInfo>>(); |
| typeMappingInfoToAdapterClasses = new HashMap<TypeMappingInfo, Class>(); |
| if (typeMappingInfos != null) { |
| for (int i = 0; i < typeMappingInfos.length; i++) { |
| List<TypeMappingInfo> infos = javaClassToTypeMappingInfos.get(classes[i]); |
| if(infos == null) { |
| infos = new ArrayList<TypeMappingInfo>(); |
| javaClassToTypeMappingInfos.put(classes[i], infos); |
| } |
| infos.add(typeMappingInfos[i]); |
| |
| java.lang.annotation.Annotation[] annotations = getAnnotations(typeMappingInfos[i]); |
| if (annotations != null) { |
| for (java.lang.annotation.Annotation nextAnnotation : annotations) { |
| if (nextAnnotation instanceof XmlJavaTypeAdapter) { |
| typeMappingInfoToAdapterClasses.put(typeMappingInfos[i], ((XmlJavaTypeAdapter) nextAnnotation).value()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Process class level annotations only. It is assumed that a call to init() |
| * has been made prior to calling this method. After the types created via |
| * this method have been modified (if necessary) postBuildTypeInfo and |
| * processJavaClasses should be called to finish processing. |
| * |
| */ |
| public Map<String, TypeInfo> preBuildTypeInfo(JavaClass[] javaClasses) { |
| for (JavaClass javaClass : javaClasses) { |
| String qualifiedName = javaClass.getQualifiedName(); |
| TypeInfo info = typeInfos.get(qualifiedName); |
| if (javaClass == null || javaClass.isArray()|| (info!=null && info.isPreBuilt()) || !shouldGenerateTypeInfo(javaClass) || isXmlRegistry(javaClass) ) { |
| continue; |
| } |
| |
| |
| if (javaClass.isEnum()) { |
| info = new EnumTypeInfo(helper, javaClass); |
| } else { |
| info = new TypeInfo(helper, javaClass); |
| } |
| info.setJavaClassName(qualifiedName); |
| info.setPreBuilt(true); |
| |
| // handle @XmlTransient |
| if (helper.isAnnotationPresent(javaClass, XmlTransient.class)) { |
| info.setXmlTransient(true); |
| } |
| |
| // handle @XmlElementNillable |
| processXmlElementNillable(javaClass, info); |
| |
| // handle @XmlExtensible |
| processXmlExtensible(javaClass, info); |
| |
| // handle @XmlInlineBinaryData |
| if (helper.isAnnotationPresent(javaClass, XmlInlineBinaryData.class)) { |
| info.setInlineBinaryData(true); |
| } |
| |
| // handle @NamedObjectGraph |
| processNamedObjectGraphs(javaClass, info); |
| |
| // handle @XmlRootElement |
| processXmlRootElement(javaClass, info); |
| |
| // handle @XmlSeeAlso |
| processXmlSeeAlso(javaClass, info); |
| |
| PackageInfo packageInfo = getPackageInfoForPackage(javaClass); |
| if(packageInfo != null && packageInfo.getPackageLevelAdaptersByClass().size() > 0){ |
| for(String adapterClass :packageInfo.getPackageLevelAdaptersByClass().keySet()){ |
| JavaClass boundType = packageInfo.getPackageLevelAdaptersByClass().get(adapterClass); |
| info.getPackageLevelAdaptersByClass().put(adapterClass, boundType); |
| } |
| } |
| NamespaceInfo namespaceInfo = packageInfo.getNamespaceInfo(); |
| // handle @XmlType |
| preProcessXmlType(javaClass, info, namespaceInfo); |
| |
| // handle @XmlAccessorType |
| preProcessXmlAccessorType(javaClass, info, namespaceInfo); |
| |
| // handle @XmlAccessorOrder |
| preProcessXmlAccessorOrder(javaClass, info, namespaceInfo); |
| |
| // handle package level @XmlJavaTypeAdapters |
| processPackageLevelAdapters(javaClass, info); |
| |
| // handle Accessor Factory |
| processAccessorFactory(javaClass, info); |
| |
| // handle class level @XmlJavaTypeAdapters |
| processClassLevelAdapters(javaClass, info); |
| |
| // handle descriptor customizer |
| preProcessCustomizer(javaClass, info); |
| |
| // handle package level @XmlSchemaType(s) |
| processSchemaTypes(javaClass, info); |
| |
| // handle class extractor |
| if (helper.isAnnotationPresent(javaClass, XmlClassExtractor.class)) { |
| XmlClassExtractor classExtractor = (XmlClassExtractor) helper.getAnnotation(javaClass, XmlClassExtractor.class); |
| info.setClassExtractorName(classExtractor.value().getName()); |
| } |
| |
| // handle user properties |
| if (helper.isAnnotationPresent(javaClass, XmlProperties.class)) { |
| XmlProperties xmlProperties = (XmlProperties) helper.getAnnotation(javaClass, XmlProperties.class); |
| Map<Object, Object> propertiesMap = createUserPropertiesMap(xmlProperties.value()); |
| info.setUserProperties(propertiesMap); |
| } else if (helper.isAnnotationPresent(javaClass, XmlProperty.class)) { |
| XmlProperty xmlProperty = (XmlProperty) helper.getAnnotation(javaClass, XmlProperty.class); |
| Map<Object, Object> propertiesMap = createUserPropertiesMap(new XmlProperty[] { xmlProperty }); |
| info.setUserProperties(propertiesMap); |
| } |
| |
| // handle class indicator field name |
| if (helper.isAnnotationPresent(javaClass, XmlDiscriminatorNode.class)) { |
| XmlDiscriminatorNode xmlDiscriminatorNode = (XmlDiscriminatorNode) helper.getAnnotation(javaClass, XmlDiscriminatorNode.class); |
| info.setXmlDiscriminatorNode(xmlDiscriminatorNode.value()); |
| } |
| // handle class indicator |
| if (helper.isAnnotationPresent(javaClass, XmlDiscriminatorValue.class)) { |
| XmlDiscriminatorValue xmlDiscriminatorValue = (XmlDiscriminatorValue) helper.getAnnotation(javaClass, XmlDiscriminatorValue.class); |
| info.setXmlDiscriminatorValue(xmlDiscriminatorValue.value()); |
| } |
| |
| typeInfoClasses.add(javaClass); |
| typeInfos.put(info.getJavaClassName(), info); |
| } |
| return typeInfos; |
| } |
| |
| private void processXmlElementNillable(JavaClass javaClass, TypeInfo info) { |
| if (helper.isAnnotationPresent(javaClass, XmlElementNillable.class)) { |
| XmlElementNillable xmlElementNillable = (XmlElementNillable) helper.getAnnotation(javaClass, XmlElementNillable.class); |
| info.setXmlElementNillable(xmlElementNillable.nillable()); |
| } else if (hasExternalPackageMapping(javaClass)) { |
| info.setXmlElementNillable(packageToXmlNillableInfoMappings.get(javaClass.getPackageName()).getXmlElementNillable().isNillable()); |
| } else if (helper.isAnnotationPresent(javaClass.getPackage(), XmlElementNillable.class)) { |
| XmlElementNillable xmlElementNillable = (XmlElementNillable) helper.getAnnotation(javaClass.getPackage(), XmlElementNillable.class); |
| info.setXmlElementNillable(xmlElementNillable.nillable()); |
| } |
| } |
| |
| private boolean hasExternalPackageMapping(JavaClass javaClass) { |
| |
| if (null == packageToXmlNillableInfoMappings || !packageToXmlNillableInfoMappings.containsKey(javaClass.getPackageName())) { |
| return false; |
| } |
| |
| return null != packageToXmlNillableInfoMappings.get(javaClass.getPackageName()).getXmlElementNillable(); |
| } |
| |
| private void processNamedObjectGraphs(JavaClass javaClass, TypeInfo info) { |
| List<XmlNamedObjectGraph> objectGraphs = new ArrayList<XmlNamedObjectGraph>(); |
| if(helper.isAnnotationPresent(javaClass, XmlNamedObjectGraphs.class)) { |
| XmlNamedObjectGraphs graphs = (XmlNamedObjectGraphs)helper.getAnnotation(javaClass, XmlNamedObjectGraphs.class); |
| Collections.addAll(objectGraphs, graphs.value()); |
| } |
| if(helper.isAnnotationPresent(javaClass, XmlNamedObjectGraph.class)) { |
| objectGraphs.add((XmlNamedObjectGraph)helper.getAnnotation(javaClass, XmlNamedObjectGraph.class)); |
| } |
| |
| for(XmlNamedObjectGraph next:objectGraphs) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNamedObjectGraph namedGraph = new org.eclipse.persistence.jaxb.xmlmodel.XmlNamedObjectGraph(); |
| namedGraph.setName(next.name()); |
| |
| for(XmlNamedAttributeNode nextNode:next.attributeNodes()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode namedNode = new org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode(); |
| namedNode.setName(nextNode.value()); |
| namedNode.setSubgraph(nextNode.subgraph()); |
| namedGraph.getXmlNamedAttributeNode().add(namedNode); |
| } |
| for(XmlNamedSubgraph nextSubgraph:next.subgraphs()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNamedSubgraph namedSubGraph = new org.eclipse.persistence.jaxb.xmlmodel.XmlNamedSubgraph(); |
| namedSubGraph.setName(nextSubgraph.name()); |
| namedSubGraph.setType(nextSubgraph.type().getName()); |
| for(XmlNamedAttributeNode nextNode:nextSubgraph.attributeNodes()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode namedNode = new org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode(); |
| namedNode.setName(nextNode.value()); |
| namedNode.setSubgraph(nextNode.subgraph()); |
| namedSubGraph.getXmlNamedAttributeNode().add(namedNode); |
| } |
| namedGraph.getXmlNamedSubgraph().add(namedSubGraph); |
| } |
| for(XmlNamedSubgraph nextSubgraph:next.subclassSubgraphs()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNamedSubgraph namedSubGraph = new org.eclipse.persistence.jaxb.xmlmodel.XmlNamedSubgraph(); |
| namedSubGraph.setName(nextSubgraph.name()); |
| namedSubGraph.setType(nextSubgraph.type().getName()); |
| for(XmlNamedAttributeNode nextNode:nextSubgraph.attributeNodes()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode namedNode = new org.eclipse.persistence.jaxb.xmlmodel.XmlNamedAttributeNode(); |
| namedNode.setName(nextNode.value()); |
| namedNode.setSubgraph(nextNode.subgraph()); |
| namedSubGraph.getXmlNamedAttributeNode().add(namedNode); |
| } |
| namedGraph.getXmlNamedSubclassGraph().add(namedSubGraph); |
| } |
| info.getObjectGraphs().add(namedGraph); |
| } |
| } |
| |
| private void processAccessorFactory(JavaClass javaClass, TypeInfo info) { |
| if (!xmlAccessorFactorySupport) { |
| return; |
| } |
| |
| Annotation xmlAccessorFactory = helper.getAnnotation(javaClass, CompilerHelper.ACCESSOR_FACTORY_ANNOTATION_CLASS); |
| Method valueMethod = null; |
| if(xmlAccessorFactory != null) { |
| valueMethod = CompilerHelper.ACCESSOR_FACTORY_VALUE_METHOD; |
| } else { |
| //try for internal annotation |
| xmlAccessorFactory = helper.getAnnotation(javaClass, CompilerHelper.INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS); |
| if(xmlAccessorFactory != null) { |
| valueMethod = CompilerHelper.INTERNAL_ACCESSOR_FACTORY_VALUE_METHOD; |
| } |
| } |
| if(xmlAccessorFactory != null) { |
| Class xmlAccessorFactoryClass = null; |
| try { |
| xmlAccessorFactoryClass = PrivilegedAccessHelper.invokeMethod(valueMethod, xmlAccessorFactory, new Object[]{}); |
| info.setXmlAccessorFactory(new AccessorFactoryWrapper(PrivilegedAccessHelper.newInstanceFromClass(xmlAccessorFactoryClass))); |
| } catch (Exception ex) { |
| throw JAXBException.errorInstantiatingAccessorFactory(xmlAccessorFactoryClass, ex); |
| } |
| } |
| PackageInfo pInfo = getPackageInfoForPackage(javaClass); |
| if(pInfo != null) { |
| info.setPackageLevelXmlAccessorFactory(pInfo.getAccessorFactory()); |
| } |
| } |
| |
| /** |
| * Process any additional classes (i.e. inner classes, @XmlSeeAlso, |
| * {@literal @XmlRegistry}, etc.) for a given set of JavaClasses, then complete |
| * building all of the required TypeInfo objects. This method |
| * is typically called after init and preBuildTypeInfo have |
| * been called. |
| * |
| * @return updated array of JavaClasses, made up of the original classes |
| * plus any additional ones |
| */ |
| public JavaClass[] postBuildTypeInfo(JavaClass[] javaClasses) { |
| if (javaClasses.length == 0) { |
| return javaClasses; |
| } |
| List<JavaClass> originalList = Arrays.asList(javaClasses); |
| // create type info instances for any additional classes |
| javaClasses = processAdditionalClasses(javaClasses); |
| preBuildTypeInfo(javaClasses); |
| buildTypeInfo(javaClasses); |
| updateGlobalElements(javaClasses); |
| if(javaClasses.length > originalList.size()) { |
| List<JavaClass> newClasses = new ArrayList<JavaClass>(javaClasses.length - originalList.size()); |
| for(JavaClass next:javaClasses) { |
| if(!(originalList.contains(next))) { |
| newClasses.add(next); |
| } |
| } |
| postBuildTypeInfo(newClasses.toArray(new JavaClass[newClasses.size()])); |
| } |
| return javaClasses; |
| } |
| |
| /** |
| * INTERNAL: |
| * |
| * Complete building TypeInfo objects for a given set of JavaClass |
| * instances. This method assumes that init, preBuildTypeInfo, and |
| * postBuildTypeInfo have been called. |
| * |
| */ |
| private Map<String, TypeInfo> buildTypeInfo(JavaClass[] allClasses) { |
| for (JavaClass javaClass : allClasses) { |
| if (javaClass == null) { |
| continue; |
| } |
| |
| TypeInfo info = typeInfos.get(javaClass.getQualifiedName()); |
| if (info == null || info.isPostBuilt()) { |
| continue; |
| } |
| info.setPostBuilt(true); |
| |
| // handle factory methods |
| processFactoryMethods(javaClass, info); |
| |
| PackageInfo packageInfo = getPackageInfoForPackage(javaClass); |
| |
| XMLNameTransformer transformer = info.getXmlNameTransformer(); |
| if(transformer == TypeInfo.DEFAULT_NAME_TRANSFORMER){ |
| XMLNameTransformer nsInfoXmlNameTransformer = packageInfo.getXmlNameTransformer(); |
| |
| if (nsInfoXmlNameTransformer != null) { |
| info.setXmlNameTransformer(nsInfoXmlNameTransformer); |
| } else if (helper.isAnnotationPresent(javaClass, XmlNameTransformer.class)) { |
| XmlNameTransformer xmlNameTransformer = (XmlNameTransformer) helper.getAnnotation(javaClass, XmlNameTransformer.class); |
| Class nameTransformerClass = xmlNameTransformer.value(); |
| try { |
| info.setXmlNameTransformer((XMLNameTransformer) nameTransformerClass.getConstructor().newInstance()); |
| } catch (ReflectiveOperationException ex) { |
| throw JAXBException.exceptionWithNameTransformerClass(nameTransformerClass.getName(), ex); |
| } |
| } else if (helper.isAnnotationPresent(javaClass.getPackage(), XmlNameTransformer.class)) { |
| XmlNameTransformer xmlNameTransformer = (XmlNameTransformer) helper.getAnnotation(javaClass.getPackage(), XmlNameTransformer.class); |
| Class nameTransformerClass = xmlNameTransformer.value(); |
| try { |
| info.setXmlNameTransformer((XMLNameTransformer) nameTransformerClass.getConstructor().newInstance()); |
| } catch (ReflectiveOperationException ex) { |
| throw JAXBException.exceptionWithNameTransformerClass(nameTransformerClass.getName(), ex); |
| } |
| } |
| } |
| |
| // handle @XmlAccessorType |
| postProcessXmlAccessorType(info, packageInfo); |
| |
| // handle @XmlType |
| postProcessXmlType(javaClass, info, packageInfo); |
| |
| // handle @XmlEnum |
| if (info.isEnumerationType()) { |
| addEnumTypeInfo(javaClass, ((EnumTypeInfo) info)); |
| continue; |
| } |
| |
| // process schema type name |
| processTypeQName(javaClass, info, packageInfo.getNamespaceInfo()); |
| |
| // handle superclass if necessary |
| JavaClass superClass = javaClass.getSuperclass(); |
| processPropertiesSuperClass(javaClass, info); |
| processReferencedClass(superClass); |
| |
| // add properties |
| info.setProperties(getPropertiesForClass(javaClass, info)); |
| |
| // process properties |
| processTypeInfoProperties(javaClass, info); |
| |
| // handle @XmlAccessorOrder |
| postProcessXmlAccessorOrder(info, packageInfo); |
| |
| validatePropOrderForInfo(info); |
| } |
| return typeInfos; |
| } |
| |
| private TypeInfo processReferencedClass(JavaClass referencedClass){ |
| if (shouldGenerateTypeInfo(referencedClass)) { |
| String qName = referencedClass.getQualifiedName(); |
| TypeInfo existingInfo = typeInfos.get(qName); |
| if (existingInfo == null || !existingInfo.isPreBuilt()) { |
| PackageInfo pInfo = getPackageInfoForPackage(referencedClass); |
| JavaClass adapterClass = pInfo.getPackageLevelAdaptersByClass().get(qName); |
| if (adapterClass == null) { |
| CompilerHelper.addClassToClassLoader(referencedClass, helper.getClassLoader()); |
| JavaClass[] jClassArray = new JavaClass[] { referencedClass }; |
| buildNewTypeInfo(jClassArray); |
| } |
| return typeInfos.get(qName); |
| } else { |
| if (!existingInfo.isPostBuilt()) { |
| PackageInfo pInfo = getPackageInfoForPackage(referencedClass); |
| JavaClass adapterClass = pInfo.getPackageLevelAdaptersByClass().get(qName); |
| if (adapterClass == null) { |
| CompilerHelper.addClassToClassLoader(referencedClass, helper.getClassLoader()); |
| JavaClass[] javaClasses = new JavaClass[] { referencedClass }; |
| javaClasses = postBuildTypeInfo(javaClasses); |
| for(JavaClass next:javaClasses) { |
| processPropertyTypes(next); |
| } |
| } |
| } |
| return existingInfo; |
| } |
| } |
| return null; |
| } |
| |
| /* |
| * Get virtual property and XmlID information from parent and set it on info if available |
| */ |
| public void processPropertiesSuperClass(JavaClass cls, TypeInfo info) { |
| JavaClass superClass = cls.getSuperclass(); |
| if (superClass == null) { |
| return; |
| } |
| TypeInfo superClassInfo = this.typeInfos.get(superClass.getQualifiedName()); |
| if(superClassInfo != null) { |
| processPropertiesSuperClass(superClass, superClassInfo); |
| classesToProcessPropertyTypes.add(superClass); |
| if(superClassInfo.getXmlVirtualAccessMethods() != null && info.getXmlVirtualAccessMethods() == null) { |
| info.setXmlVirtualAccessMethods(superClassInfo.getXmlVirtualAccessMethods()); |
| } |
| if(superClassInfo.isIDSet()){ |
| info.setIDProperty(superClassInfo.getIDProperty()); |
| } |
| } |
| } |
| |
| /** |
| * Perform any final generation and/or validation operations on TypeInfo |
| * properties. |
| * |
| */ |
| public void finalizeProperties() { |
| |
| for (TypeInfo tInfo: getTypeInfos().values()) { |
| // don't need to validate props on a transient class at this point |
| if (tInfo.isTransient()) { |
| continue; |
| } |
| JavaClass jClass = tInfo.getJavaClass(); |
| String[] propOrder = tInfo.getPropOrder(); |
| boolean hasPropOrder = propOrder.length > 0 && !(propOrder.length == 1 && propOrder[0].equals(Constants.EMPTY_STRING)); |
| // If a property is marked transient, ensure it doesn't exist in the propOrder |
| List<String> propOrderList = Arrays.asList(tInfo.getPropOrder()); |
| List<Property> propsList = tInfo.getPropertyList(); |
| for (Property p : propsList) { |
| if (p.isTransient() && propOrderList.contains(p.getPropertyName())) { |
| throw JAXBException.transientInProporder(p.getPropertyName(), tInfo.getJavaClassName()); |
| } |
| if (hasPropOrder && !p.isAttribute() && !p.isTransient() && !p.isInverseReference()) { |
| if (!propOrderList.contains(p.getPropertyName())) { |
| throw JAXBException.missingPropertyInPropOrder(p.getPropertyName(), tInfo.getJavaClassName()); |
| } |
| } |
| } |
| |
| if (!jClass.isInterface() && !tInfo.isEnumerationType() && !jClass.isAbstract()) { |
| if (tInfo.getFactoryMethodName() == null && tInfo.getObjectFactoryClassName() == null) { |
| JavaConstructor zeroArgConstructor = jClass.getDeclaredConstructor(new JavaClass[] {}); |
| if (zeroArgConstructor == null) { |
| if (tInfo.isSetXmlJavaTypeAdapter()) { |
| tInfo.setTransient(true); |
| } else { |
| if(!referencedByTransformer.contains(jClass.getName())){ |
| throw org.eclipse.persistence.exceptions.JAXBException.factoryMethodOrConstructorRequired(jClass.getName()); |
| } |
| } |
| } |
| } |
| } |
| // validate XmlValue |
| if (tInfo.getXmlValueProperty() != null) { |
| validateXmlValueFieldOrProperty(jClass, tInfo.getXmlValueProperty()); |
| } |
| |
| // Keep a list of "any" properties to verify if multiples exist |
| // that they have different element wrappers |
| List<Property> anyElementProperties = new ArrayList<Property>(); |
| |
| for (Property property : tInfo.getPropertyList()) { |
| // Check that @XmlAttribute references a Java type that maps to text in XML |
| if (property.isAttribute()) { |
| validateXmlAttributeFieldOrProperty(tInfo, property); |
| } |
| JavaClass propertyClass = property.getActualType(); |
| |
| if (property.isChoice()) { |
| Collection<Property> choiceProps = property.getChoiceProperties(); |
| for (Property nextChoiceProp : choiceProps) { |
| JavaClass nextChoicePropTypeClass = nextChoiceProp.getActualType(); |
| TypeInfo targetInfo = typeInfos.get(nextChoicePropTypeClass.getQualifiedName()); |
| finalizeProperty(property, targetInfo, nextChoicePropTypeClass, jClass); |
| } |
| } else { |
| TypeInfo targetInfo = typeInfos.get(propertyClass.getQualifiedName()); |
| finalizeProperty(property, targetInfo, propertyClass, jClass); |
| } |
| |
| // only one XmlValue is allowed per class, and if there is one |
| // only XmlAttributes are allowed |
| if (tInfo.isSetXmlValueProperty()) { |
| if (property.isXmlValue() && !(tInfo.getXmlValueProperty().getPropertyName().equals(property.getPropertyName()))) { |
| throw JAXBException.xmlValueAlreadySet(property.getPropertyName(), tInfo.getXmlValueProperty().getPropertyName(), jClass.getName()); |
| } |
| if (!property.isXmlValue() && !property.isAttribute() && !property.isInverseReference() && !property.isTransient()) { |
| throw JAXBException.propertyOrFieldShouldBeAnAttribute(property.getPropertyName(), jClass.getName()); |
| } |
| } |
| |
| |
| // handle XmlElementRef(s) - validate and build the required |
| // ElementDeclaration object |
| if (property.isReference()) { |
| processReferenceProperty(property, tInfo, jClass); |
| } |
| |
| if (property.isSwaAttachmentRef() && !this.hasSwaRef) { |
| this.hasSwaRef = true; |
| } |
| |
| if (property.isXmlId()) { |
| // there can only be one XmlID per type info |
| if (tInfo.getIDProperty() != null && !(tInfo.getIDProperty().getPropertyName().equals(property.getPropertyName()))) { |
| throw JAXBException.idAlreadySet(property.getPropertyName(), tInfo.getIDProperty().getPropertyName(), jClass.getName()); |
| } |
| |
| // XmlID property should be of java.lang.String type |
| validateXmlIdStringType(property); |
| } |
| |
| // there can only be one XmlAnyAttribute per type info |
| if (property.isAnyAttribute() && tInfo.isSetAnyAttributePropertyName() && !(tInfo.getAnyAttributePropertyName().equals(property.getPropertyName()))) { |
| throw JAXBException.multipleAnyAttributeMapping(jClass.getName()); |
| } |
| // there can only be one XmlAnyElement per type info |
| if (property.isAny()) { |
| if(!anyElementProperties.isEmpty()) { |
| for(Property nextAny:anyElementProperties) { |
| if(!property.isSetXmlElementWrapper() && !nextAny.isSetXmlElementWrapper()) { |
| throw JAXBException.xmlAnyElementAlreadySet(property.getPropertyName(), nextAny.getPropertyName(), jClass.getName()); |
| } |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper wrapper = property.getXmlElementWrapper(); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper targetWrapper = nextAny.getXmlElementWrapper(); |
| if(wrapper != null && targetWrapper != null) { |
| if(wrapper.getName().equals(targetWrapper.getName()) && wrapper.getNamespace().equals(targetWrapper.getNamespace())) { |
| throw JAXBException.xmlAnyElementAlreadySet(property.getPropertyName(), nextAny.getPropertyName(), jClass.getName()); |
| } |
| } |
| } |
| } |
| anyElementProperties.add(property); |
| } |
| // an XmlAttachmentRef can only appear on a DataHandler property |
| if (property.isSwaAttachmentRef() && !areEquals(property.getActualType(), JAVAX_ACTIVATION_DATAHANDLER)) { |
| throw JAXBException.invalidAttributeRef(property.getPropertyName(), jClass.getQualifiedName()); |
| } |
| // an XmlElementWrapper can only appear on a Collection or Array |
| if (property.getXmlElementWrapper() != null) { |
| if (!helper.isCollectionType(property.getType()) && !property.getType().isArray() && !helper.isMapType(property.getType())) { |
| throw JAXBException.invalidElementWrapper(property.getPropertyName()); |
| } |
| } |
| |
| // handle XmlTransformation - validate transformer class/method |
| if (property.isXmlTransformation()) { |
| validateXmlTransformationProperty(property); |
| } |
| // validate XmlJoinNodes |
| if (property.isSetXmlJoinNodes()) { |
| TypeInfo targetInfo = typeInfos.get(propertyClass.getQualifiedName()); |
| |
| // the target class must have an associated TypeInfo |
| if (targetInfo == null) { |
| throw JAXBException.invalidXmlJoinNodeReferencedClass(property.getPropertyName(), propertyClass.getQualifiedName()); |
| } |
| // validate each referencedXmlPath - target TypeInfo should |
| // have XmlID/XmlKey property with matching XmlPath |
| if (targetInfo.getIDProperty() == null && targetInfo.getXmlKeyProperties() == null) { |
| throw JAXBException.noKeyOrIDPropertyOnJoinTarget(jClass.getQualifiedName(), property.getPropertyName(), propertyClass.getQualifiedName()); |
| } |
| } |
| } |
| } |
| } |
| |
| private void validateXmlIdStringType(Property property) { |
| if (!"java.lang.String".equals(property.getActualType().getQualifiedName()) && !MOXySystemProperties.xmlIdExtension && !helper.isAnnotationPresent(property.getElement(), XmlIDExtension.class) && !property.isXmlIdExtension()) { |
| throw JAXBException.invalidId(property.getPropertyName()); |
| } |
| } |
| |
| private void finalizeProperty(Property property, TypeInfo targetInfo, JavaClass typeClass, JavaClass jClass){ |
| if (targetInfo != null && targetInfo.isTransient() && property.getXmlElements() == null) { |
| property.setTransientType(true); |
| } |
| |
| // validate XmlIDREF |
| if (property.isXmlIdRef()) { |
| // the target class must have an associated TypeInfo unless |
| // it is Object |
| if (targetInfo == null && !typeClass.getQualifiedName().equals(JAVA_LANG_OBJECT)) { |
| throw JAXBException.invalidIDREFClass(jClass.getQualifiedName(), property.getPropertyName(), typeClass.getQualifiedName()); |
| } |
| // if the property is an XmlIDREF, the target must have an |
| // XmlID set |
| if (targetInfo != null && targetInfo.getIDProperty() == null && !preCheckXmlID(typeClass, targetInfo)) { |
| throw JAXBException.invalidIdRef(property.getPropertyName(), typeClass.getQualifiedName()); |
| } |
| } |
| } |
| |
| /** |
| * Process a given TypeInfo instance's properties. |
| * |
| */ |
| private void processTypeInfoProperties(JavaClass javaClass, TypeInfo info) { |
| List<Property> properties = info.getPropertyList(); |
| for (Property property : properties) { |
| // handle @XmlID |
| processXmlID(property, javaClass, info); |
| |
| // handle @XmlIDREF - validate these properties after processing of |
| // all types is completed |
| processXmlIDREF(property); |
| |
| if (property.isMap()){ |
| processReferencedClass(property.getKeyType()); |
| processReferencedClass(property.getActualValueType()); |
| } |
| } |
| } |
| |
| void processPropertyTypes(JavaClass[] classes) { |
| for (JavaClass next : classes) { |
| processPropertyTypes(next); |
| classesToProcessPropertyTypes.remove(next); |
| } |
| for (int i =0; i< classesToProcessPropertyTypes.size(); i++) { // throws cme when using foreach |
| JavaClass next = classesToProcessPropertyTypes.get(i); |
| processPropertyTypes(next); |
| } |
| } |
| |
| private void processPropertyTypes(JavaClass next){ |
| |
| TypeInfo info = getTypeInfos().get(next.getQualifiedName()); |
| if (info != null) { |
| for (Property property : info.getPropertyList()) { |
| if (property.isXmlLocation()) |
| info.setLocationAware(true); |
| if (property.isTransient()) |
| continue; |
| |
| JavaClass type = property.getActualType(); |
| if (property.isReference()) { |
| processReferencePropertyTypes(property, info, next); |
| } |
| if (property.isChoice()) { |
| processChoiceProperty(property, info, next, type); |
| for (Property choiceProp : property.getChoiceProperties()) { |
| type = choiceProp.getActualType(); |
| processReferencedClass(type); |
| } |
| } else { |
| processReferencedClass(type); |
| } |
| } |
| } |
| |
| } |
| |
| /** |
| * Process any additional classes, such as inner classes, @XmlRegistry or |
| * from @XmlSeeAlso. |
| * |
| */ |
| private JavaClass[] processAdditionalClasses(JavaClass[] classes) { |
| ArrayList<JavaClass> extraClasses = new ArrayList<JavaClass>(); |
| ArrayList<JavaClass> classesToProcess = new ArrayList<JavaClass>(); |
| for (JavaClass jClass : classes) { |
| List<TypeMappingInfo> infos = this.javaClassToTypeMappingInfos.get(jClass); |
| if(infos != null && infos.size() > 0) { |
| for(TypeMappingInfo next:infos) { |
| processAdditionalClasses(jClass, next, extraClasses, classesToProcess); |
| } |
| } else { |
| processAdditionalClasses(jClass, null, extraClasses, classesToProcess); |
| } |
| } |
| // process @XmlRegistry, @XmlSeeAlso and inner classes |
| for (JavaClass javaClass : extraClasses) { |
| processClass(javaClass, classesToProcess); |
| } |
| |
| return classesToProcess.toArray(new JavaClass[classesToProcess.size()]); |
| } |
| |
| private void processAdditionalClasses(JavaClass cls, TypeMappingInfo tmi, ArrayList<JavaClass> extraClasses, ArrayList<JavaClass> classesToProcess) { |
| Class xmlElementType = null; |
| JavaClass javaClass = cls; |
| if (tmi != null) { |
| Class adapterClass = this.typeMappingInfoToAdapterClasses.get(tmi); |
| if (adapterClass != null) { |
| JavaClass adapterJavaClass = helper.getJavaClass(adapterClass); |
| JavaClass newType = helper.getJavaClass(Object.class); |
| |
| // look for marshal method |
| for (Object nextMethod : adapterJavaClass.getDeclaredMethods()) { |
| JavaMethod method = (JavaMethod) nextMethod; |
| if (method.getName().equals("marshal")) { |
| JavaClass returnType = method.getReturnType(); |
| if (!returnType.getQualifiedName().equals(newType.getQualifiedName())) { |
| newType = returnType; |
| break; |
| } |
| } |
| } |
| if (!helper.isBuiltInJavaType(javaClass)) { |
| extraClasses.add(javaClass); |
| } |
| javaClass = newType; |
| } |
| java.lang.annotation.Annotation[] annotations = getAnnotations(tmi); |
| if (annotations != null) { |
| for (Annotation nextAnnotation : annotations) { |
| if (nextAnnotation != null && nextAnnotation instanceof XmlElement) { |
| XmlElement javaAnnotation = (XmlElement) nextAnnotation; |
| if (javaAnnotation.type() != XmlElement.DEFAULT.class) { |
| xmlElementType = javaAnnotation.type(); |
| } |
| } |
| } |
| } |
| } |
| |
| if (areEquals(javaClass, byte[].class) || areEquals(javaClass, JAVAX_ACTIVATION_DATAHANDLER) || areEquals(javaClass, Source.class) || areEquals(javaClass, Image.class) || areEquals(javaClass, JAVAX_MAIL_INTERNET_MIMEMULTIPART)) { |
| if (tmi == null || tmi.getXmlTagName() == null) { |
| ElementDeclaration declaration = new ElementDeclaration(null, javaClass, javaClass.getQualifiedName(), false, XmlElementDecl.GLOBAL.class); |
| declaration.setTypeMappingInfo(tmi); |
| this.localElements.add(declaration); |
| } |
| } else if (javaClass.isArray()) { |
| if (!helper.isBuiltInJavaType(javaClass.getComponentType())) { |
| extraClasses.add(javaClass.getComponentType()); |
| } |
| Class generatedClass; |
| if (null == tmi) { |
| generatedClass = arrayClassesToGeneratedClasses.get(javaClass.getName()); |
| } else { |
| generatedClass = CompilerHelper.getExisitingGeneratedClass(tmi, typeMappingInfosToGeneratedClasses, typeMappingInfoToAdapterClasses, helper.getClassLoader()); |
| } |
| if (generatedClass == null) { |
| generatedClass = generateWrapperForArrayClass(javaClass, tmi, xmlElementType, extraClasses); |
| extraClasses.add(helper.getJavaClass(generatedClass)); |
| arrayClassesToGeneratedClasses.put(javaClass.getName(), generatedClass); |
| } |
| generatedClassesToArrayClasses.put(generatedClass, javaClass); |
| typeMappingInfosToGeneratedClasses.put(tmi, generatedClass); |
| |
| } else if (helper.isCollectionType(javaClass)) { |
| JavaClass componentClass; |
| Collection args = javaClass.getActualTypeArguments(); |
| if (!args.isEmpty()) { |
| componentClass = (JavaClass) args.iterator().next(); |
| if (!componentClass.isPrimitive()) { |
| extraClasses.add(componentClass); |
| } |
| } else { |
| componentClass = helper.getJavaClass(Object.class); |
| } |
| |
| Class generatedClass = CompilerHelper.getExisitingGeneratedClass(tmi, typeMappingInfosToGeneratedClasses, typeMappingInfoToAdapterClasses, helper.getClassLoader()); |
| if (generatedClass == null) { |
| generatedClass = generateCollectionValue(javaClass, tmi, xmlElementType, extraClasses); |
| extraClasses.add(helper.getJavaClass(generatedClass)); |
| } |
| typeMappingInfosToGeneratedClasses.put(tmi, generatedClass); |
| } else if (helper.isMapType(javaClass)) { |
| JavaClass keyClass; |
| JavaClass valueClass; |
| Collection args = javaClass.getActualTypeArguments(); |
| Iterator argsIter = args.iterator(); |
| if (!args.isEmpty()) { |
| keyClass = (JavaClass) argsIter.next(); |
| if (!helper.isBuiltInJavaType(keyClass)) { |
| extraClasses.add(keyClass); |
| } |
| valueClass = (JavaClass) argsIter.next(); |
| if (!helper.isBuiltInJavaType(valueClass)) { |
| extraClasses.add(valueClass); |
| } |
| } else { |
| keyClass = helper.getJavaClass(Object.class); |
| valueClass = helper.getJavaClass(Object.class); |
| } |
| |
| Class generatedClass = CompilerHelper.getExisitingGeneratedClass(tmi, typeMappingInfosToGeneratedClasses, typeMappingInfoToAdapterClasses, helper.getClassLoader()); |
| if (generatedClass == null) { |
| generatedClass = generateWrapperForMapClass(javaClass, keyClass, valueClass, tmi); |
| extraClasses.add(helper.getJavaClass(generatedClass)); |
| } |
| typeMappingInfosToGeneratedClasses.put(tmi, generatedClass); |
| } else { |
| // process @XmlRegistry, @XmlSeeAlso and inner classes |
| processClass(javaClass, classesToProcess); |
| } |
| } |
| |
| /** |
| * Adds additional classes to the given List, from inner classes, |
| * |
| * See @XmlRegistry or @XmlSeeAlso. |
| * |
| */ |
| private void processClass(JavaClass javaClass, ArrayList<JavaClass> classesToProcess) { |
| if (shouldGenerateTypeInfo(javaClass)) { |
| if (isXmlRegistry(javaClass)) { |
| this.processObjectFactory(javaClass, classesToProcess); |
| } else { |
| classesToProcess.add(javaClass); |
| // handle @XmlSeeAlso |
| TypeInfo info = typeInfos.get(javaClass.getQualifiedName()); |
| if (info != null && info.isSetXmlSeeAlso()) { |
| for (String jClassName : info.getXmlSeeAlso()) { |
| classesToProcess.add(helper.getJavaClass(jClassName)); |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * Process an @XmlSeeAlso annotation. TypeInfo instances will be created for |
| * each class listed. |
| * |
| */ |
| private void processXmlSeeAlso(JavaClass javaClass, TypeInfo info) { |
| // reflectively load @XmlSeeAlso class to avoid dependency |
| Class xmlSeeAlsoClass = null; |
| Method valueMethod = null; |
| try { |
| xmlSeeAlsoClass = PrivilegedAccessHelper.getClassForName("jakarta.xml.bind.annotation.XmlSeeAlso", false, helper.getClassLoader()); |
| valueMethod = PrivilegedAccessHelper.getDeclaredMethod(xmlSeeAlsoClass, "value", new Class[] {}); |
| } catch (ClassNotFoundException ex) { |
| // Ignore this exception. If SeeAlso isn't available, don't try to |
| // process |
| } catch (NoSuchMethodException ex) { |
| } |
| if (xmlSeeAlsoClass != null && helper.isAnnotationPresent(javaClass, xmlSeeAlsoClass)) { |
| Object seeAlso = helper.getAnnotation(javaClass, xmlSeeAlsoClass); |
| Class[] values = null; |
| try { |
| values = PrivilegedAccessHelper.invokeMethod(valueMethod, seeAlso, new Object[] {}); |
| } catch (Exception ex) { |
| } |
| |
| if (values != null) { |
| List<String> seeAlsoClassNames = new ArrayList<String>(); |
| for (Class next : values) { |
| seeAlsoClassNames.add(next.getName()); |
| } |
| info.setXmlSeeAlso(seeAlsoClassNames); |
| } |
| } |
| } |
| |
| /** |
| * Process any factory methods. |
| * |
| */ |
| private void processFactoryMethods(JavaClass javaClass, TypeInfo info) { |
| JavaMethod factoryMethod = this.factoryMethods.get(javaClass.getRawName()); |
| if (factoryMethod != null) { |
| // set up factory method info for mappings. |
| info.setFactoryMethodName(factoryMethod.getName()); |
| info.setObjectFactoryClassName(factoryMethod.getOwningClass().getQualifiedName()); |
| JavaClass[] paramTypes = factoryMethod.getParameterTypes(); |
| if (paramTypes != null && paramTypes.length > 0) { |
| String[] paramTypeNames = new String[paramTypes.length]; |
| for (int i = 0; i < paramTypes.length; i++) { |
| processReferencedClass(paramTypes[i]); |
| paramTypeNames[i] = paramTypes[i].getQualifiedName(); |
| } |
| info.setFactoryMethodParamTypes(paramTypeNames); |
| } |
| } |
| } |
| |
| /** |
| * Process any package-level @XmlJavaTypeAdapters. |
| * |
| */ |
| private void processPackageLevelAdapters(JavaClass javaClass, TypeInfo info) { |
| JavaPackage pack = javaClass.getPackage(); |
| if (helper.isAnnotationPresent(pack, XmlJavaTypeAdapters.class)) { |
| XmlJavaTypeAdapters adapters = (XmlJavaTypeAdapters) helper.getAnnotation(pack, XmlJavaTypeAdapters.class); |
| XmlJavaTypeAdapter[] adapterArray = adapters.value(); |
| for (XmlJavaTypeAdapter next : adapterArray) { |
| processPackageLevelAdapter(next, info); |
| } |
| } |
| |
| if (helper.isAnnotationPresent(pack, XmlJavaTypeAdapter.class)) { |
| XmlJavaTypeAdapter adapter = (XmlJavaTypeAdapter) helper.getAnnotation(pack, XmlJavaTypeAdapter.class); |
| processPackageLevelAdapter(adapter, info); |
| } |
| } |
| |
| private void processPackageLevelAdapter(XmlJavaTypeAdapter next, TypeInfo info) { |
| JavaClass adapterClass = helper.getJavaClass(next.value()); |
| JavaClass boundType = helper.getJavaClass(next.type()); |
| if (boundType != null) { |
| info.addPackageLevelAdapterClass(adapterClass, boundType); |
| } else { |
| getLogger().logWarning(JAXBMetadataLogger.INVALID_BOUND_TYPE, new Object[] { null, adapterClass }); |
| } |
| } |
| |
| /** |
| * Process any class-level @XmlJavaTypeAdapters. |
| * |
| */ |
| private void processClassLevelAdapters(JavaClass javaClass, TypeInfo info) { |
| if (helper.isAnnotationPresent(javaClass, XmlJavaTypeAdapter.class)) { |
| XmlJavaTypeAdapter adapter = (XmlJavaTypeAdapter) helper.getAnnotation(javaClass, XmlJavaTypeAdapter.class); |
| String boundType = adapter.type().getName(); |
| |
| if (boundType == null || boundType.equals("jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT")) { |
| boundType = javaClass.getRawName(); |
| } |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xja = new org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter(); |
| xja.setValue(adapter.value().getName()); |
| xja.setType(boundType); |
| |
| info.setXmlJavaTypeAdapter(xja); |
| } |
| } |
| |
| /** |
| * Process any @XmlSchemaType(s). |
| * |
| */ |
| private void processSchemaTypes(JavaClass javaClass, TypeInfo info) { |
| JavaPackage pack = javaClass.getPackage(); |
| if (helper.isAnnotationPresent(pack, XmlSchemaTypes.class)) { |
| XmlSchemaTypes types = (XmlSchemaTypes) helper.getAnnotation(pack, XmlSchemaTypes.class); |
| XmlSchemaType[] typeArray = types.value(); |
| for (XmlSchemaType next : typeArray) { |
| processSchemaType(next); |
| } |
| } else if (helper.isAnnotationPresent(pack, XmlSchemaType.class)) { |
| processSchemaType((XmlSchemaType) helper.getAnnotation(pack, XmlSchemaType.class)); |
| } |
| } |
| |
| /** |
| * Process @XmlRootElement annotation on a given JavaClass. |
| * |
| */ |
| private void processXmlRootElement(JavaClass javaClass, TypeInfo info) { |
| if (helper.isAnnotationPresent(javaClass, XmlRootElement.class)) { |
| XmlRootElement rootElemAnnotation = (XmlRootElement) helper.getAnnotation(javaClass, XmlRootElement.class); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement xmlRE = new org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement(); |
| xmlRE.setName(rootElemAnnotation.name()); |
| xmlRE.setNamespace(rootElemAnnotation.namespace()); |
| info.setXmlRootElement(xmlRE); |
| } |
| } |
| |
| /** |
| * Process @XmlExtensible annotation on a given JavaClass. |
| * |
| */ |
| private void processXmlExtensible(JavaClass javaClass, TypeInfo info) { |
| if (helper.isAnnotationPresent(javaClass, XmlVirtualAccessMethods.class)) { |
| XmlVirtualAccessMethods extAnnotation = (XmlVirtualAccessMethods) helper.getAnnotation(javaClass, XmlVirtualAccessMethods.class); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlVirtualAccessMethods xmlExt = new org.eclipse.persistence.jaxb.xmlmodel.XmlVirtualAccessMethods(); |
| xmlExt.setGetMethod(extAnnotation.getMethod()); |
| xmlExt.setSetMethod(extAnnotation.setMethod()); |
| xmlExt.setSchema(org.eclipse.persistence.jaxb.xmlmodel.XmlVirtualAccessMethodsSchema.valueOf(extAnnotation.schema().toString())); |
| info.setXmlVirtualAccessMethods(xmlExt); |
| } |
| } |
| |
| /** |
| * Process @XmlType annotation on a given JavaClass and update the TypeInfo |
| * for pre-processing. Note that if no @XmlType annotation is present we |
| * still create a new XmlType an set it on the TypeInfo. |
| * |
| */ |
| private void preProcessXmlType(JavaClass javaClass, TypeInfo info, NamespaceInfo packageNamespace) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlType xmlType = new org.eclipse.persistence.jaxb.xmlmodel.XmlType(); // 14 xmlType=XmlType - default settings: name=null, namespace=null, factoryClass=null, factoryMethod=null, propOrder=null. |
| if (helper.isAnnotationPresent(javaClass, XmlType.class)) { |
| XmlType typeAnnotation = (XmlType) helper.getAnnotation(javaClass, XmlType.class); // 15 typeAnnotation=com.sun.proxy.$Proxy6"@jakarta.xml.bind.annotation.XmlType(factoryMethod=, name=OneClass, propOrder=[car], factoryClass=class jakarta.xml.bind.annotation.XmlType$DEFAULT, namespace=##default)" |
| // set name |
| xmlType.setName(typeAnnotation.name()); // 16 XmlType - name="OneClass |
| // set namespace |
| xmlType.setNamespace(typeAnnotation.namespace()); // 17 xmlType - namespace="##default" |
| // set propOrder |
| String[] propOrder = typeAnnotation.propOrder(); // 18 propOrder = ["car"] |
| // initializes xmlType.propOrder to an empty ArrayList |
| if (propOrder != null) { |
| xmlType.getPropOrder(); // 19 OK, so this only initializes xmlType.propOrder to an empty ArrayList |
| } |
| for (String prop : propOrder) { |
| xmlType.getPropOrder().add(prop); // 20 - puts "car" into xmlType.propOrder |
| } |
| // set factoryClass |
| Class factoryClass = typeAnnotation.factoryClass(); // 21 factoryClass=java.lang.Class"class jakarta.xml.bind.annotation.XmlType$DEFAULT" |
| if (factoryClass == DEFAULT.class) { |
| xmlType.setFactoryClass("jakarta.xml.bind.annotation.XmlType.DEFAULT"); // 22 |
| } else { |
| xmlType.setFactoryClass(factoryClass.getCanonicalName()); |
| } |
| // set factoryMethodName |
| xmlType.setFactoryMethod(typeAnnotation.factoryMethod()); // 23 defaults to factoryMethod="" |
| } else { |
| // set defaults |
| xmlType.setNamespace(packageNamespace.getNamespace()); |
| } |
| info.setXmlType(xmlType); // 24 |
| } |
| |
| /** |
| * Process XmlType for a given TypeInfo. Here we assume that the TypeInfo |
| * has an XmlType set - typically via preProcessXmlType or XmlProcessor |
| * override. |
| * |
| */ |
| private void postProcessXmlType(JavaClass javaClass, TypeInfo info, PackageInfo packageNamespace) { |
| // assumes that the TypeInfo has an XmlType set from |
| org.eclipse.persistence.jaxb.xmlmodel.XmlType xmlType = info.getXmlType(); |
| |
| // set/validate factoryClass and factoryMethod |
| String factoryClassName = xmlType.getFactoryClass(); |
| String factoryMethodName = xmlType.getFactoryMethod(); |
| |
| if (factoryClassName.equals("jakarta.xml.bind.annotation.XmlType.DEFAULT")) { |
| if (factoryMethodName != null && !factoryMethodName.equals(EMPTY_STRING)) { |
| // factory method applies to the current class - verify method |
| // exists |
| JavaMethod method = javaClass.getDeclaredMethod(factoryMethodName, new JavaClass[] {}); |
| if (method == null) { |
| throw org.eclipse.persistence.exceptions.JAXBException.factoryMethodNotDeclared(factoryMethodName, javaClass.getName()); |
| } |
| info.setFactoryMethodName(factoryMethodName); |
| } |
| } else { |
| if (factoryMethodName == null || factoryMethodName.equals(EMPTY_STRING)) { |
| throw org.eclipse.persistence.exceptions.JAXBException.factoryClassWithoutFactoryMethod(javaClass.getName()); |
| } |
| info.setObjectFactoryClassName(factoryClassName); |
| info.setFactoryMethodName(factoryMethodName); |
| } |
| |
| // figure out type name |
| String typeName = xmlType.getName(); |
| if (typeName.equals(XMLProcessor.DEFAULT)) { |
| try { |
| typeName = info.getXmlNameTransformer().transformTypeName(javaClass.getName()); |
| } catch (Exception ex) { |
| throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex); |
| } |
| } |
| info.setSchemaTypeName(typeName); |
| |
| // set propOrder |
| if (xmlType.isSetPropOrder()) { |
| List<String> props = xmlType.getPropOrder(); |
| if (props.size() == 0) { |
| info.setPropOrder(new String[0]); |
| } else if (props.get(0).equals(EMPTY_STRING)) { |
| info.setPropOrder(new String[] { EMPTY_STRING }); |
| } else { |
| info.setPropOrder(xmlType.getPropOrder().toArray(new String[xmlType.getPropOrder().size()])); |
| } |
| } |
| |
| // figure out namespace |
| if (xmlType.getNamespace().equals(XMLProcessor.DEFAULT)) { |
| info.setClassNamespace(packageNamespace.getNamespace()); |
| } else { |
| info.setClassNamespace(xmlType.getNamespace()); |
| } |
| } |
| |
| /** |
| * Process @XmlAccessorType annotation on a given JavaClass and update the |
| * TypeInfo for pre-processing. |
| * |
| */ |
| private void preProcessXmlAccessorType(JavaClass javaClass, TypeInfo info, NamespaceInfo packageNamespace) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlAccessType xmlAccessType; |
| if (javaClass.getDeclaredAnnotation(helper.getJavaClass(XmlAccessorType.class)) != null) { |
| XmlAccessorType accessorType = (XmlAccessorType) helper.getAnnotation(javaClass, XmlAccessorType.class); |
| xmlAccessType = org.eclipse.persistence.jaxb.xmlmodel.XmlAccessType.fromValue(accessorType.value().name()); |
| info.setXmlAccessType(xmlAccessType); |
| } |
| } |
| |
| /** |
| * Post process XmlAccessorType. In some cases, such as @XmlSeeAlso classes, |
| * the access type may not have been set |
| * |
| */ |
| private void postProcessXmlAccessorType(TypeInfo info, PackageInfo packageNamespace) { |
| if (!info.isSetXmlAccessType()) { |
| // Check for super class |
| JavaClass next = helper.getJavaClass(info.getJavaClassName()).getSuperclass(); |
| while (next != null && !(next.getName().equals(JAVA_LANG_OBJECT))) { |
| processReferencedClass(next); |
| TypeInfo parentInfo = this.typeInfos.get(next.getName()); |
| if (parentInfo != null && parentInfo.isSetXmlAccessType()) { |
| info.setXmlAccessType(parentInfo.getXmlAccessType()); |
| break; |
| } |
| next = next.getSuperclass(); |
| } |
| // use value in package-info.java as last resort - will default if |
| // not set |
| if(!(info.isSetXmlAccessType())) { |
| info.setXmlAccessType(org.eclipse.persistence.jaxb.xmlmodel.XmlAccessType.fromValue(packageNamespace.getAccessType().name())); |
| } |
| } |
| } |
| |
| /** |
| * Process package and class @XmlAccessorOrder. Class level annotation |
| * overrides a package level annotation. |
| * |
| */ |
| private void preProcessXmlAccessorOrder(JavaClass javaClass, TypeInfo info, NamespaceInfo packageNamespace) { |
| XmlAccessorOrder order = null; |
| // class level annotation overrides package level annotation |
| if (helper.isAnnotationPresent(javaClass, XmlAccessorOrder.class)) { |
| order = (XmlAccessorOrder) helper.getAnnotation(javaClass, XmlAccessorOrder.class); |
| info.setXmlAccessOrder(XmlAccessOrder.fromValue(order.value().name())); |
| } |
| } |
| |
| /** |
| * Post process XmlAccessorOrder. This method assumes that the given |
| * TypeInfo has already had its order set (via annotations in |
| * preProcessXmlAccessorOrder or via xml metadata override in XMLProcessor). |
| * |
| */ |
| private void postProcessXmlAccessorOrder(TypeInfo info, PackageInfo packageNamespace) { |
| if (!info.isSetXmlAccessOrder()) { |
| // use value in package-info.java as last resort - will default if |
| // not set |
| info.setXmlAccessOrder(org.eclipse.persistence.jaxb.xmlmodel.XmlAccessOrder.fromValue(packageNamespace.getAccessOrder().name())); |
| } |
| info.orderProperties(); |
| } |
| |
| /** |
| * Process @XmlElement annotation on a given property. |
| * |
| */ |
| private void processXmlElement(Property property, TypeInfo info) { |
| |
| if (helper.isAnnotationPresent(property.getElement(), XmlElementNillable.class)) { |
| XmlElementNillable elementNillable = (XmlElementNillable) helper.getAnnotation(property.getElement(), XmlElementNillable.class); |
| property.setNillable(elementNillable.nillable()); |
| } else if (info.isXmlElementNillable()) { |
| property.setNillable(true); |
| } |
| |
| if (helper.isAnnotationPresent(property.getElement(), XmlElement.class)) { |
| XmlElement element = (XmlElement) helper.getAnnotation(property.getElement(), XmlElement.class); |
| property.setIsRequired(element.required()); |
| property.setNillable(element.nillable()); |
| if (element.type() != XmlElement.DEFAULT.class && !(property.isSwaAttachmentRef())) { |
| property.setOriginalType(property.getType()); |
| if (helper.isCollectionType(property.getType()) || property.getType().isArray()) { |
| property.setGenericType(helper.getJavaClass(element.type())); |
| } else { |
| JavaClass originalType = property.getType(); |
| JavaClass newType =helper.getJavaClass(element.type()); |
| if(!originalType.getName().equals(newType.getName())){ |
| property.setTyped(true); |
| property.setSchemaType((QName) helper.getXMLToJavaTypeMap().get(newType.getName())); |
| } |
| property.setType(newType); |
| } |
| property.setHasXmlElementType(true); |
| } |
| // handle default value |
| if (!element.defaultValue().equals(ELEMENT_DECL_DEFAULT)) { |
| property.setDefaultValue(element.defaultValue()); |
| } |
| |
| if (facets) addFacets(property); |
| } |
| } |
| |
| /** |
| * @since 2.6 |
| * @author Marcel Valovy |
| * @param property property for which facets will be generated |
| */ |
| private void addFacets(Property property) { |
| final JavaHasAnnotations element = property.getElement(); |
| if (helper.isAnnotationPresent(element, DecimalMin.class)) { |
| DecimalMin a = (DecimalMin) helper.getAnnotation(element, DecimalMin.class); |
| DecimalMinFacet facet = new DecimalMinFacet(a.value(), a.inclusive()); |
| property.addFacet(facet); |
| } |
| if (helper.isAnnotationPresent(element, DecimalMax.class)) { |
| DecimalMax a = (DecimalMax) helper.getAnnotation(element, DecimalMax.class); |
| DecimalMaxFacet facet = new DecimalMaxFacet(a.value(), a.inclusive()); |
| property.addFacet(facet); |
| } |
| if (helper.isAnnotationPresent(element, Digits.class)) { |
| Digits a = (Digits) helper.getAnnotation(element, Digits.class); |
| DigitsFacet facet = new DigitsFacet(a.integer(), a.fraction()); |
| property.addFacet(facet); |
| } |
| if (helper.isAnnotationPresent(element, Max.class)) { |
| Max a = (Max) helper.getAnnotation(element, Max.class); |
| MaxFacet facet = new MaxFacet(a.value()); |
| property.addFacet(facet); |
| } |
| if (helper.isAnnotationPresent(element, Min.class)) { |
| Min a = (Min) helper.getAnnotation(element, Min.class); |
| MinFacet facet = new MinFacet(a.value()); |
| property.addFacet(facet); |
| } |
| if (helper.isAnnotationPresent(element, NotNull.class)) { |
| property.setNotNullAnnotated(true); |
| } |
| if (helper.isAnnotationPresent(element, Pattern.class)) { |
| Pattern a = (Pattern) helper.getAnnotation(element, Pattern.class); |
| PatternFacet facet = new PatternFacet(a.regexp(), a.flags()); |
| property.addFacet(facet); |
| } |
| /* Example: |
| @Pattern.List({ |
| @Pattern(regexp = "first_expression", message = "first.Pattern.message"), |
| @Pattern(regexp = "second_expression", message = "second.Pattern.message"), |
| @Pattern(regexp = "third_expression", message = "third.Pattern.message") |
| }) */ |
| if (helper.isAnnotationPresent(element, Pattern.List.class)) { |
| Pattern.List a = (Pattern.List) helper.getAnnotation(element, Pattern.List.class); |
| PatternListFacet facet = new PatternListFacet(new ArrayList<PatternFacet>()); |
| for (Pattern pat : a.value()) { |
| PatternFacet pf = new PatternFacet(pat.regexp(), pat.flags()); |
| facet.addPattern(pf); |
| } |
| property.addFacet(facet); |
| } |
| if (helper.isAnnotationPresent(element, Size.class)) { |
| Size a = (Size) helper.getAnnotation(element, Size.class); |
| final int min = a.min(); |
| final int max = a.max(); |
| if (min != 0 || max != Integer.MAX_VALUE) { // Fixes generation of an empty facet. |
| if ("java.lang.String".equals(property.getType().getName())) { // @Size serves for both length facet and occurs restriction. |
| SizeFacet facet = new SizeFacet(min, max); // For minLength, maxLength. |
| property.addFacet(facet); |
| } else { // For minOccurs, maxOccurs. |
| if (min > 0) property.setMinOccurs(min); // 0 is default minBoundary. |
| if (max < Integer.MAX_VALUE) property.setMaxOccurs(max); // 2^31 is default maxBoundary. |
| } |
| } |
| } |
| } |
| |
| /** |
| * Process @XmlID annotation on a given property |
| * |
| */ |
| private void processXmlID(Property property, JavaClass javaClass, TypeInfo info) { |
| if (helper.isAnnotationPresent(property.getElement(), XmlID.class)) { |
| property.setIsXmlId(true); |
| info.setIDProperty(property); |
| } |
| } |
| |
| /** |
| * Process @XmlIDREF on a given property. |
| * |
| */ |
| private void processXmlIDREF(Property property) { |
| if (helper.isAnnotationPresent(property.getElement(), XmlIDREF.class)) { |
| property.setIsXmlIdRef(true); |
| } |
| } |
| |
| /** |
| * Process @XmlJavaTypeAdapter on a given property. |
| * |
| */ |
| private void processXmlJavaTypeAdapter(Property property, TypeInfo info, JavaClass javaClass) { |
| JavaClass adapterClass = null; |
| JavaClass ptype = property.getActualType(); |
| if (helper.isAnnotationPresent(property.getElement(), XmlJavaTypeAdapter.class)) { |
| XmlJavaTypeAdapter adapter = (XmlJavaTypeAdapter) helper.getAnnotation(property.getElement(), XmlJavaTypeAdapter.class); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xja = new org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter(); |
| xja.setValue(adapter.value().getName()); |
| xja.setType(adapter.type().getName()); |
| property.setXmlJavaTypeAdapter(xja); |
| } else { |
| TypeInfo ptypeInfo = typeInfos.get(ptype.getQualifiedName()); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xmlJavaTypeAdapter; |
| if (ptypeInfo == null && shouldGenerateTypeInfo(ptype)) { |
| if (helper.isAnnotationPresent(ptype, XmlJavaTypeAdapter.class)) { |
| XmlJavaTypeAdapter adapter = (XmlJavaTypeAdapter) helper.getAnnotation(ptype, XmlJavaTypeAdapter.class); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xja = new org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter(); |
| xja.setValue(adapter.value().getName()); |
| /*String boundType = adapter.type().getName(); |
| if (boundType == null || boundType.equals("jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter.DEFAULT")) { |
| boundType = ptype.getRawName(); |
| } value from boundType is not used - fix if you know what it should do. */ |
| xja.setType(adapter.type().getName()); |
| property.setXmlJavaTypeAdapter(xja); |
| } |
| } |
| if (ptypeInfo != null) { |
| if (null != (xmlJavaTypeAdapter = ptypeInfo.getXmlJavaTypeAdapter())) { |
| try { |
| property.setXmlJavaTypeAdapter(xmlJavaTypeAdapter); |
| } catch (JAXBException e) { |
| throw JAXBException.invalidTypeAdapterClass(xmlJavaTypeAdapter.getValue(), javaClass.getName()); |
| } |
| } |
| } |
| if(info.hasPackageLevelAdaptersByClass()) { |
| if (info.getPackageLevelAdaptersByClass().get(ptype.getQualifiedName()) != null && !property.isSetXmlJavaTypeAdapter()) { |
| adapterClass = info.getPackageLevelAdapterClass(ptype); |
| |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xja = new org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter(); |
| xja.setValue(adapterClass.getQualifiedName()); |
| xja.setType(ptype.getQualifiedName()); |
| property.setXmlJavaTypeAdapter(xja); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Store a QName (if necessary) based on a given TypeInfo's schema type |
| * name. |
| * |
| */ |
| private void processTypeQName(JavaClass javaClass, TypeInfo info, NamespaceInfo packageNamespace) { |
| if(info.isTransient()) { |
| return; |
| } |
| String typeName = info.getSchemaTypeName(); |
| if (typeName != null && !(EMPTY_STRING.equals(typeName))) { |
| QName typeQName = new QName(info.getClassNamespace(), typeName); |
| |
| boolean containsQName = typeQNames.contains(typeQName); |
| if (containsQName) { |
| throw JAXBException.nameCollision(typeQName.getNamespaceURI(), typeQName.getLocalPart()); |
| } else { |
| typeQNames.add(typeQName); |
| } |
| } |
| } |
| |
| public boolean shouldGenerateTypeInfo(JavaClass javaClass) { |
| if (javaClass == null || javaClass.isPrimitive() || javaClass.isAnnotation() || ORG_W3C_DOM.equals(javaClass.getPackageName())) { |
| return false; |
| } |
| if (userDefinedSchemaTypes.get(javaClass.getQualifiedName()) != null) { |
| return false; |
| } |
| if (javaClass.isArray()) { |
| String javaClassName = javaClass.getName(); |
| if (!(javaClassName.equals(CoreClassConstants.APBYTE.getName()))&& !(javaClassName.equals(CoreClassConstants.ABYTE.getName()))) { |
| return true; |
| } |
| } |
| if (helper.isBuiltInJavaType(javaClass) && !javaClass.isEnum()) { |
| return false; |
| } |
| if (helper.isCollectionType(javaClass) || helper.isMapType(javaClass)) { |
| return false; |
| } |
| return true; |
| } |
| |
| public ArrayList<Property> getPropertiesForClass(JavaClass cls, TypeInfo info) { |
| ArrayList<Property> returnList = new ArrayList<Property>(); |
| |
| if (!info.isTransient()) { |
| JavaClass superClass = cls.getSuperclass(); |
| if (null != superClass) { |
| TypeInfo superClassInfo = typeInfos.get(superClass.getQualifiedName()); |
| ArrayList<Property> superClassProperties; |
| while (superClassInfo != null && superClassInfo.isTransient()) { |
| if (info.getXmlAccessType() == XmlAccessType.FIELD) { |
| superClassProperties = getFieldPropertiesForClass(superClass, superClassInfo, false); |
| } else if (info.getXmlAccessType() == XmlAccessType.PROPERTY) { |
| superClassProperties = getPropertyPropertiesForClass(superClass, superClassInfo, false); |
| } else if (info.getXmlAccessType() == XmlAccessType.PUBLIC_MEMBER) { |
| superClassProperties = getPublicMemberPropertiesForClass(superClass, superClassInfo); |
| } else { |
| superClassProperties = getNoAccessTypePropertiesForClass(superClass, superClassInfo); |
| } |
| superClass = superClass.getSuperclass(); |
| superClassInfo = typeInfos.get(superClass.getQualifiedName()); |
| for(Property next:superClassProperties) { |
| next.setIsSuperClassProperty(true); |
| } |
| returnList.addAll(0, superClassProperties); |
| } |
| } |
| } |
| |
| if (info.isTransient()) { |
| returnList.addAll(getNoAccessTypePropertiesForClass(cls, info)); |
| } else if (info.getXmlAccessType() == XmlAccessType.FIELD) { |
| returnList.addAll(getFieldPropertiesForClass(cls, info, false)); |
| returnList.addAll(getPropertyPropertiesForClass(cls, info, false, true)); |
| } else if (info.getXmlAccessType() == XmlAccessType.PROPERTY) { |
| returnList.addAll(getFieldPropertiesForClass(cls, info, false, true)); |
| returnList.addAll(getPropertyPropertiesForClass(cls, info, false)); |
| } else if (info.getXmlAccessType() == XmlAccessType.PUBLIC_MEMBER) { |
| returnList.addAll(getPublicMemberPropertiesForClass(cls, info)); |
| } else { |
| returnList.addAll(getNoAccessTypePropertiesForClass(cls, info)); |
| } |
| return returnList; |
| } |
| |
| public ArrayList<Property> getFieldPropertiesForClass(JavaClass cls, TypeInfo info, boolean onlyPublic) { |
| return getFieldPropertiesForClass(cls, info, onlyPublic, false); |
| } |
| |
| public ArrayList<Property> getFieldPropertiesForClass(JavaClass cls, TypeInfo info, boolean onlyPublic, boolean onlyExplicit) { |
| ArrayList<Property> properties = new ArrayList<Property>(); |
| if (cls == null) { |
| return properties; |
| } |
| |
| for (JavaField javaField : (Iterable<JavaField>) cls.getDeclaredFields()) { |
| Property property = null; |
| int modifiers = javaField.getModifiers(); |
| |
| if (!Modifier.isTransient(modifiers) && ((Modifier.isPublic(javaField.getModifiers()) && onlyPublic) || !onlyPublic || hasJAXBAnnotations(javaField))) { |
| if (!Modifier.isStatic(modifiers)) { |
| if ((onlyExplicit && hasJAXBAnnotations(javaField)) || !onlyExplicit) { |
| try { |
| property = buildNewProperty(info, cls, javaField, javaField.getName(), javaField.getResolvedType()); |
| properties.add(property); |
| } catch (JAXBException ex) { |
| if (ex.getErrorCode() != JAXBException.INVALID_INTERFACE || !helper.isAnnotationPresent(javaField, XmlTransient.class)) { |
| throw ex; |
| } |
| } |
| } |
| } else { |
| try { |
| property = buildNewProperty(info, cls, javaField, javaField.getName(), javaField.getResolvedType()); |
| if (helper.isAnnotationPresent(javaField, XmlAttribute.class)) { |
| Object value = ((JavaFieldImpl) javaField).get(null); |
| if (value != null) { |
| String stringValue = XMLConversionManager.getDefaultXMLManager().convertObject(value, String.class, property.getSchemaType()); |
| property.setFixedValue(stringValue); |
| } |
| } |
| property.setWriteOnly(true); |
| if (!hasJAXBAnnotations(javaField)) { |
| property.setTransient(true); |
| } |
| properties.add(property); |
| } catch (ClassCastException e) { |
| // do Nothing |
| } catch (IllegalAccessException e) { |
| // do Nothing |
| } catch (JAXBException ex) { |
| if (ex.getErrorCode() != JAXBException.INVALID_INTERFACE || !helper.isAnnotationPresent(javaField, XmlTransient.class)) { |
| throw ex; |
| } |
| } |
| } |
| } |
| |
| if (helper.isAnnotationPresent(javaField, XmlTransient.class)) { |
| if (property != null) { |
| property.setTransient(true); |
| } |
| } |
| } |
| return properties; |
| } |
| |
| /* |
| * Create a new Property Object and process the annotations that are common |
| * to fields and methods |
| */ |
| Property buildNewProperty(TypeInfo info, JavaClass cls, JavaHasAnnotations javaHasAnnotations, String propertyName, JavaClass ptype) { |
| Property property = null; |
| if (helper.isAnnotationPresent(javaHasAnnotations, XmlElements.class)) { |
| property = buildChoiceProperty(javaHasAnnotations); |
| } else if (helper.isAnnotationPresent(javaHasAnnotations, XmlElementRef.class) || helper.isAnnotationPresent(javaHasAnnotations, XmlElementRefs.class)) { |
| |
| findAndProcessObjectFactory(cls); |
| |
| property = buildReferenceProperty(info, javaHasAnnotations, propertyName, ptype); |
| if (helper.isAnnotationPresent(javaHasAnnotations, XmlAnyElement.class)) { |
| XmlAnyElement anyElement = (XmlAnyElement) helper.getAnnotation(javaHasAnnotations, XmlAnyElement.class); |
| property.setIsAny(true); |
| if (anyElement.value() != null) { |
| property.setDomHandlerClassName(anyElement.value().getName()); |
| } |
| property.setLax(anyElement.lax()); |
| info.setAnyElementPropertyName(propertyName); |
| } |
| } else if (helper.isAnnotationPresent(javaHasAnnotations, XmlAnyElement.class)) { |
| findAndProcessObjectFactory(cls); |
| XmlAnyElement anyElement = (XmlAnyElement) helper.getAnnotation(javaHasAnnotations, XmlAnyElement.class); |
| property = new Property(helper); |
| property.setIsAny(true); |
| if (anyElement.value() != null) { |
| property.setDomHandlerClassName(anyElement.value().getName()); |
| } |
| property.setLax(anyElement.lax()); |
| info.setAnyElementPropertyName(propertyName); |
| } else if (helper.isAnnotationPresent(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlTransformation.class) || helper.isAnnotationPresent(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlReadTransformer.class) || helper.isAnnotationPresent(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlWriteTransformer.class) || helper.isAnnotationPresent(javaHasAnnotations, XmlWriteTransformers.class)) { |
| property = buildTransformationProperty(javaHasAnnotations, cls); |
| } else { |
| property = new Property(helper); |
| } |
| property.setPropertyName(propertyName); |
| property.setElement(javaHasAnnotations); |
| |
| // if there is a TypeInfo for ptype check it for transient, otherwise |
| // check the class |
| if (helper.isCollectionType(ptype)) { |
| JavaClass componentType = helper.getJavaClass(Object.class); |
| |
| Collection typeArgs = ptype.getActualTypeArguments(); |
| if(!typeArgs.isEmpty()) { |
| componentType = (JavaClass) typeArgs.iterator().next(); |
| } |
| updatePropertyType(property, ptype, componentType); |
| }else{ |
| updatePropertyType(property, ptype, ptype); |
| } |
| |
| if(helper.isAnnotationPresent(javaHasAnnotations, XmlVariableNode.class)){ |
| XmlVariableNode variableNode = (XmlVariableNode) helper.getAnnotation(javaHasAnnotations, XmlVariableNode.class); |
| if(variableNode.type() != XmlVariableNode.DEFAULT.class){ |
| property.setVariableClassName(variableNode.type().getName()); |
| |
| JavaClass componentType = helper.getJavaClass(variableNode.type()); |
| |
| if(helper.isCollectionType(ptype)){ |
| property.setGenericType(componentType); |
| }else{ |
| property.setType(componentType); |
| } |
| |
| } |
| if(!variableNode.value().equals("##default")){ |
| property.setVariableAttributeName(variableNode.value()); |
| } |
| property.setVariableNodeAttribute(variableNode.attribute()); |
| } |
| |
| |
| if((ptype.isArray() && !areEquals(ptype, byte[].class)) || (helper.isCollectionType(ptype) && !helper.isAnnotationPresent(javaHasAnnotations, XmlList.class)) ){ |
| property.setNillable(true); |
| } |
| processPropertyAnnotations(info, cls, javaHasAnnotations, property); |
| |
| if (helper.isAnnotationPresent(javaHasAnnotations, XmlPath.class)) { |
| XmlPath xmlPath = (XmlPath) helper.getAnnotation(javaHasAnnotations, XmlPath.class); |
| property.setXmlPath(xmlPath.value()); |
| Field tempField = new XMLField(xmlPath.value()); |
| boolean isAttribute = tempField.getLastXPathFragment().isAttribute(); |
| property.setIsAttribute(isAttribute); |
| // set schema name |
| String schemaName = XMLProcessor.getNameFromXPath(xmlPath.value(), property.getPropertyName(), isAttribute); |
| QName qName; |
| NamespaceInfo nsInfo = getPackageInfoForPackage(cls).getNamespaceInfo(); |
| if(isAttribute){ |
| if (nsInfo.isAttributeFormQualified()) { |
| qName = new QName(nsInfo.getNamespace(), schemaName); |
| } else { |
| qName = new QName(schemaName); |
| } |
| }else{ |
| if (nsInfo.isElementFormQualified()) { |
| qName = new QName(nsInfo.getNamespace(), schemaName); |
| } else { |
| qName = new QName(schemaName); |
| } |
| } |
| property.setSchemaName(qName); |
| //create properties for any predicates |
| XPathFragment fragment = tempField.getXPathFragment(); |
| String currentPath = ""; |
| while(fragment != null && !(fragment.nameIsText()) && !(fragment.isAttribute())) { |
| if(fragment.getPredicate() != null) { |
| //can't append xpath directly since it will contain the predicate |
| String fragmentPath = fragment.getLocalName(); |
| if(fragment.getPrefix() != null && !(Constants.EMPTY_STRING.equals(fragment.getPrefix()))) { |
| fragmentPath = fragment.getPrefix() + ":" + fragmentPath; |
| } |
| currentPath += fragmentPath; |
| String predicatePath = currentPath; |
| TypeInfo targetInfo = info; |
| if(fragment.getNextFragment() == null) { |
| //if this is the last fragment, and there's no text after, then this is |
| //complex. May need to add the attribute property to the target type. |
| processReferencedClass(ptype); |
| TypeInfo predicateTypeInfo = typeInfos.get(ptype.getQualifiedName()); |
| if(predicateTypeInfo != null) { |
| targetInfo = predicateTypeInfo; |
| predicatePath = ""; |
| } |
| } |
| Property predicateProperty = new Property(helper); |
| predicateProperty.setType(helper.getJavaClass("java.lang.String")); |
| if(predicatePath.length() > 0) { |
| predicatePath += "/"; |
| } |
| predicatePath += fragment.getPredicate().getXPathFragment().getXPath(); |
| predicateProperty.setXmlPath(predicatePath); |
| predicateProperty.setIsAttribute(true); |
| |
| String predschemaName = XMLProcessor.getNameFromXPath(predicatePath, property.getPropertyName(), true); |
| QName predQname; |
| if (nsInfo.isAttributeFormQualified()) { |
| predQname = new QName(nsInfo.getNamespace(), predschemaName); |
| } else { |
| predQname = new QName(predschemaName); |
| } |
| predicateProperty.setSchemaName(predQname); |
| |
| if(!targetInfo.hasPredicateProperty(predicateProperty)) { |
| targetInfo.getPredicateProperties().add(predicateProperty); |
| } |
| } else { |
| currentPath += fragment.getXPath(); |
| } |
| currentPath += "/"; |
| fragment = fragment.getNextFragment(); |
| } |
| |
| } else { |
| property.setSchemaName(getQNameForProperty(property, propertyName, javaHasAnnotations, getPackageInfoForPackage(cls).getNamespaceInfo(), info)); |
| } |
| |
| ptype = property.getActualType(); |
| if (ptype.isPrimitive()) { |
| if (property.getType().isArray() && helper.isAnnotationPresent(javaHasAnnotations, XmlElement.class)) { |
| XmlElement elemAnno = (XmlElement) helper.getAnnotation(javaHasAnnotations, XmlElement.class); |
| property.setIsRequired(elemAnno.required()); |
| } else { |
| property.setIsRequired(true); |
| } |
| } |
| |
| // apply class level adapters - don't override property level adapter |
| if (!property.isSetXmlJavaTypeAdapter()) { |
| TypeInfo refClassInfo = getTypeInfos().get(ptype.getQualifiedName()); |
| if (refClassInfo != null && refClassInfo.isSetXmlJavaTypeAdapter()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJavaTypeAdapter xmlJavaTypeAdapter = null; |
| try { |
| xmlJavaTypeAdapter = refClassInfo.getXmlJavaTypeAdapter(); |
| property.setXmlJavaTypeAdapter(refClassInfo.getXmlJavaTypeAdapter()); |
| } catch (JAXBException e) { |
| throw JAXBException.invalidTypeAdapterClass(xmlJavaTypeAdapter.getValue(), cls.getName()); |
| } |
| } |
| } |
| |
| if(property.isXmlTransformation()){ |
| referencedByTransformer.add(property.getType().getName()); |
| } |
| return property; |
| } |
| |
| |
| private void updatePropertyType(Property property, JavaClass ptype, JavaClass componentType){ |
| TypeInfo componentTypeInfo = typeInfos.get(componentType.getQualifiedName()); |
| if((componentTypeInfo != null && !componentTypeInfo.isTransient()) || !helper.isAnnotationPresent(componentType, XmlTransient.class)){ |
| property.setType(ptype); |
| }else{ |
| JavaClass parent = componentType.getSuperclass(); |
| while (parent != null) { |
| if (parent.getName().equals(JAVA_LANG_OBJECT)) { |
| property.setTransientType(true); |
| property.setType(ptype); |
| break; |
| } |
| // if there is a TypeInfo for parent check it for transient, |
| // otherwise check the class |
| TypeInfo parentTypeInfo = typeInfos.get(parent.getQualifiedName()); |
| if ((parentTypeInfo != null && !parentTypeInfo.isTransient()) || !helper.isAnnotationPresent(parent, XmlTransient.class)) { |
| property.setType(parent); |
| break; |
| } |
| parent = parent.getSuperclass(); |
| } |
| } |
| } |
| |
| /** |
| * Build a new 'choice' property. Here, we flag a new property as a 'choice' |
| * and create/set an XmlModel XmlElements object based on the @XmlElements |
| * annotation. |
| * |
| * Validation and building of the XmlElement properties will be done during |
| * finalizeProperties in the processChoiceProperty method. |
| * |
| */ |
| private Property buildChoiceProperty(JavaHasAnnotations javaHasAnnotations) { |
| Property choiceProperty = new Property(helper); |
| choiceProperty.setChoice(true); |
| boolean isIdRef = helper.isAnnotationPresent(javaHasAnnotations, XmlIDREF.class); |
| choiceProperty.setIsXmlIdRef(isIdRef); |
| // build an XmlElement to set on the Property |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElements xmlElements = new org.eclipse.persistence.jaxb.xmlmodel.XmlElements(); |
| XmlElement[] elements = ((XmlElements) helper.getAnnotation(javaHasAnnotations, XmlElements.class)).value(); |
| for (XmlElement next : elements) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElement xmlElement = new org.eclipse.persistence.jaxb.xmlmodel.XmlElement(); |
| xmlElement.setDefaultValue(next.defaultValue()); |
| xmlElement.setName(next.name()); |
| xmlElement.setNamespace(next.namespace()); |
| xmlElement.setNillable(next.nillable()); |
| xmlElement.setRequired(next.required()); |
| xmlElement.setType(next.type().getName()); |
| xmlElements.getXmlElement().add(xmlElement); |
| } |
| choiceProperty.setXmlElements(xmlElements); |
| |
| // handle XmlElementsJoinNodes |
| if (helper.isAnnotationPresent(javaHasAnnotations, XmlElementsJoinNodes.class)) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes xmlJoinNodes; |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode xmlJoinNode; |
| List<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes> xmlJoinNodesList = new ArrayList<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes>(); |
| List<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode> xmlJoinNodeList = null; |
| |
| for (XmlJoinNodes xmlJNs : ((XmlElementsJoinNodes) helper.getAnnotation(javaHasAnnotations, XmlElementsJoinNodes.class)).value()) { |
| xmlJoinNodeList = new ArrayList<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode>(); |
| for (XmlJoinNode xmlJN : xmlJNs.value()) { |
| xmlJoinNode = new org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode(); |
| xmlJoinNode.setXmlPath(xmlJN.xmlPath()); |
| xmlJoinNode.setReferencedXmlPath(xmlJN.referencedXmlPath()); |
| xmlJoinNodeList.add(xmlJoinNode); |
| } |
| if (xmlJoinNodeList.size() > 0) { |
| xmlJoinNodes = new org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes(); |
| xmlJoinNodes.setXmlJoinNode(xmlJoinNodeList); |
| xmlJoinNodesList.add(xmlJoinNodes); |
| } |
| } |
| choiceProperty.setXmlJoinNodesList(xmlJoinNodesList); |
| } |
| return choiceProperty; |
| } |
| |
| private Property buildTransformationProperty(JavaHasAnnotations javaHasAnnotations, JavaClass cls) { |
| Property property = new Property(helper); |
| org.eclipse.persistence.oxm.annotations.XmlTransformation transformationAnnotation = (org.eclipse.persistence.oxm.annotations.XmlTransformation) helper.getAnnotation(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlTransformation.class); |
| XmlTransformation transformation = new XmlTransformation(); |
| if (transformationAnnotation != null) { |
| transformation.setOptional(transformationAnnotation.optional()); |
| } |
| |
| // Read Transformer |
| org.eclipse.persistence.oxm.annotations.XmlReadTransformer readTransformer = (org.eclipse.persistence.oxm.annotations.XmlReadTransformer) helper.getAnnotation(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlReadTransformer.class); |
| if (readTransformer != null) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlReadTransformer xmlReadTransformer = new org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlReadTransformer(); |
| if (!(readTransformer.transformerClass() == AttributeTransformer.class)) { |
| xmlReadTransformer.setTransformerClass(readTransformer.transformerClass().getName()); |
| } else if (!(readTransformer.method().equals(EMPTY_STRING))) { |
| xmlReadTransformer.setMethod(readTransformer.method()); |
| } |
| transformation.setXmlReadTransformer(xmlReadTransformer); |
| } |
| |
| // Handle Write Transformers |
| org.eclipse.persistence.oxm.annotations.XmlWriteTransformer[] transformers = null; |
| if (helper.isAnnotationPresent(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlWriteTransformer.class)) { |
| org.eclipse.persistence.oxm.annotations.XmlWriteTransformer writeTransformer = (org.eclipse.persistence.oxm.annotations.XmlWriteTransformer) helper.getAnnotation(javaHasAnnotations, org.eclipse.persistence.oxm.annotations.XmlWriteTransformer.class); |
| transformers = new org.eclipse.persistence.oxm.annotations.XmlWriteTransformer[] { writeTransformer }; |
| } else if (helper.isAnnotationPresent(javaHasAnnotations, XmlWriteTransformers.class)) { |
| XmlWriteTransformers writeTransformers = (XmlWriteTransformers) helper.getAnnotation(javaHasAnnotations, XmlWriteTransformers.class); |
| transformers = writeTransformers.value(); |
| } |
| |
| if (transformers != null) { |
| for (org.eclipse.persistence.oxm.annotations.XmlWriteTransformer next : transformers) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlWriteTransformer xmlWriteTransformer = new org.eclipse.persistence.jaxb.xmlmodel.XmlTransformation.XmlWriteTransformer(); |
| if (!(next.transformerClass() == FieldTransformer.class)) { |
| xmlWriteTransformer.setTransformerClass(next.transformerClass().getName()); |
| } else if (!(next.method().equals(EMPTY_STRING))) { |
| xmlWriteTransformer.setMethod(next.method()); |
| } |
| xmlWriteTransformer.setXmlPath(next.xmlPath()); |
| transformation.getXmlWriteTransformer().add(xmlWriteTransformer); |
| } |
| } |
| property.setXmlTransformation(transformation); |
| property.setIsXmlTransformation(true); |
| return property; |
| } |
| |
| /** |
| * Complete creation of a 'choice' property. Here, a Property is created for |
| * each XmlElement in the XmlElements list. Validation is performed as well. |
| * Each created Property is added to the owning Property's list of choice |
| * properties. |
| * |
| */ |
| private void processChoiceProperty(Property choiceProperty, TypeInfo info, JavaClass cls, JavaClass propertyType) { |
| String propertyName = choiceProperty.getPropertyName(); |
| |
| // validate XmlElementsXmlJoinNodes (if set) |
| if (choiceProperty.isSetXmlJoinNodesList()) { |
| // there must be one XmlJoinNodes entry per XmlElement |
| if (choiceProperty.getXmlElements().getXmlElement().size() != choiceProperty.getXmlJoinNodesList().size()) { |
| throw JAXBException.incorrectNumberOfXmlJoinNodesOnXmlElements(propertyName, cls.getQualifiedName()); |
| } |
| } |
| |
| XmlPath[] paths = null; |
| if (helper.isAnnotationPresent(choiceProperty.getElement(), XmlPaths.class)) { |
| XmlPaths pathAnnotation = (XmlPaths) helper.getAnnotation(choiceProperty.getElement(), XmlPaths.class); |
| paths = pathAnnotation.value(); |
| } |
| List<Property> choiceProperties = new ArrayList<Property>(); |
| for (int i = 0; i < choiceProperty.getXmlElements().getXmlElement().size(); i++) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElement next = choiceProperty.getXmlElements().getXmlElement().get(i); |
| Property choiceProp = new Property(helper); |
| |
| String name; |
| String namespace; |
| |
| choiceProp.setNillable(next.isNillable()); |
| choiceProp.setIsRequired(next.isRequired()); |
| // handle XmlPath - if xml-path is set, we ignore name/namespace |
| if (paths != null && next.getXmlPath() == null) { |
| // Only set the path, if the path hasn't already been set from |
| // xml |
| XmlPath nextPath = paths[i]; |
| next.setXmlPath(nextPath.value()); |
| } |
| if (next.getXmlPath() != null) { |
| choiceProp.setXmlPath(next.getXmlPath()); |
| boolean isAttribute = new XMLField(next.getXmlPath()).getLastXPathFragment().isAttribute(); |
| // validate attribute - must be in nested path, not at root |
| if (isAttribute && !next.getXmlPath().contains(SLASH)) { |
| throw JAXBException.invalidXmlPathWithAttribute(propertyName, cls.getQualifiedName(), next.getXmlPath()); |
| } |
| choiceProp.setIsAttribute(isAttribute); |
| name = XMLProcessor.getNameFromXPath(next.getXmlPath(), propertyName, isAttribute); |
| namespace = XMLProcessor.DEFAULT; |
| } else { |
| // no xml-path, so use name/namespace from xml-element |
| name = next.getName(); |
| namespace = next.getNamespace(); |
| } |
| |
| if (name == null || name.equals(XMLProcessor.DEFAULT)) { |
| if (next.getJavaAttribute() != null) { |
| name = next.getJavaAttribute(); |
| } else { |
| name = propertyName; |
| } |
| } |
| |
| // if the property has xml-idref, the target type of each |
| // xml-element in the list must have an xml-id property |
| if (choiceProperty.isXmlIdRef()) { |
| |
| JavaClass nextCls = helper.getJavaClass(next.getType()); |
| processReferencedClass(nextCls); |
| TypeInfo tInfo = typeInfos.get(next.getType()); |
| |
| |
| if (tInfo == null || (!tInfo.isIDSet() && !preCheckXmlID(nextCls, tInfo))) { |
| throw JAXBException.invalidXmlElementInXmlElementsList(propertyName, name); |
| } |
| } |
| |
| QName qName = null; |
| if (!namespace.equals(XMLProcessor.DEFAULT)) { |
| qName = new QName(namespace, name); |
| } else { |
| NamespaceInfo namespaceInfo = getPackageInfoForPackage(cls).getNamespaceInfo(); |
| if (namespaceInfo.isElementFormQualified()) { |
| qName = new QName(namespaceInfo.getNamespace(), name); |
| } else { |
| qName = new QName(name); |
| } |
| } |
| |
| choiceProp.setPropertyName(name); |
| // figure out the property's type - note that for DEFAULT, if from |
| // XML the value will |
| // be "XmlElement.DEFAULT", and from annotations the value will be |
| // "XmlElement$DEFAULT" |
| if (next.getType().equals("jakarta.xml.bind.annotation.XmlElement.DEFAULT") || next.getType().equals("jakarta.xml.bind.annotation.XmlElement$DEFAULT")) { |
| choiceProp.setType(propertyType); |
| } else { |
| choiceProp.setType(helper.getJavaClass(next.getType())); |
| } |
| // handle case of XmlJoinNodes w/XmlElements |
| if (choiceProperty.isSetXmlJoinNodesList()) { |
| // assumes one corresponding xml-join-nodes entry per |
| // xml-element |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes xmlJoinNodes = choiceProperty.getXmlJoinNodesList().get(i); |
| if (xmlJoinNodes != null) { |
| choiceProp.setXmlJoinNodes(xmlJoinNodes); |
| // set type |
| if (!xmlJoinNodes.getType().equals(XMLProcessor.DEFAULT)) { |
| JavaClass pType = helper.getJavaClass(xmlJoinNodes.getType()); |
| if (helper.isCollectionType(choiceProp.getType())) { |
| choiceProp.setGenericType(pType); |
| } else { |
| choiceProp.setType(pType); |
| } |
| } |
| } |
| } |
| |
| choiceProp.setSchemaName(qName); |
| choiceProp.setSchemaType(getSchemaTypeFor(choiceProp.getType())); |
| choiceProp.setIsXmlIdRef(choiceProperty.isXmlIdRef()); |
| choiceProp.setXmlElementWrapper(choiceProperty.getXmlElementWrapper()); |
| choiceProperties.add(choiceProp); |
| processReferencedClass(choiceProp.getType()); |
| TypeInfo newInfo = typeInfos.get(choiceProp.getType().getQualifiedName()); |
| if (newInfo != null && newInfo.isTransient()) { |
| throw JAXBException.invalidReferenceToTransientClass(info.getJavaClassName(), choiceProperty.getPropertyName(), newInfo.getJavaClassName()); |
| } |
| } |
| choiceProperty.setChoiceProperties(choiceProperties); |
| } |
| |
| /** |
| * Check if class with specified non complete type info has @XmlID field. |
| * Can update type info. Used in case when annotation processor analyze |
| * inheritance (parent classes) and from parent class is reverse reference |
| * via @XmlIDREF, @XmlPaths and @XmlElements to the some child classes. |
| * In this phase type info is not complete (missing properties). |
| */ |
| private boolean preCheckXmlID(JavaClass javaClass, TypeInfo typeInfo) { |
| ArrayList<Property> properties = getPropertiesForClass(javaClass, typeInfo); |
| for (Property property : properties) { |
| // check @XmlID |
| if (helper.isAnnotationPresent(property.getElement(), XmlID.class)) { |
| return true; |
| } |
| } |
| if (typeInfos.get(javaClass.getSuperclass().getQualifiedName()).isIDSet()) { |
| if (typeInfo.getIDProperty() == null) { |
| typeInfo.setIDProperty(typeInfos.get(javaClass.getSuperclass().getQualifiedName()).getIDProperty()); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Build a reference property. Here we will build a list of XML model |
| * XmlElementRef objects, based on the @XmlElement(s) annotation, to store |
| * on the Property. Processing of the elements and validation will be |
| * performed during the finalize property phase via the |
| * processReferenceProperty method. |
| * |
| */ |
| private Property buildReferenceProperty(TypeInfo info, JavaHasAnnotations javaHasAnnotations, String propertyName, JavaClass ptype) { |
| Property property = new Property(helper); |
| property.setType(ptype); |
| |
| XmlElementRef[] elementRefs; |
| XmlElementRef ref = (XmlElementRef) helper.getAnnotation(javaHasAnnotations, XmlElementRef.class); |
| if (ref != null) { |
| elementRefs = new XmlElementRef[] { ref }; |
| } else { |
| XmlElementRefs refs = (XmlElementRefs) helper.getAnnotation(javaHasAnnotations, XmlElementRefs.class); |
| elementRefs = refs.value(); |
| info.setElementRefsPropertyName(propertyName); |
| } |
| |
| List<org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef> eltRefs = new ArrayList<org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef>(); |
| for (XmlElementRef nextRef : elementRefs) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef eltRef = new org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef(); |
| eltRef.setName(nextRef.name()); |
| eltRef.setNamespace(nextRef.namespace()); |
| eltRef.setType(nextRef.type().getName()); |
| property.setIsRequired(true); |
| try{ |
| Method requireMethod = PrivilegedAccessHelper.getMethod(XmlElementRef.class, "required", new Class[0], true); |
| if(requireMethod != null){ |
| Boolean val = PrivilegedAccessHelper.invokeMethod(requireMethod, nextRef); |
| property.setIsRequired(val); |
| } |
| } catch (Exception exception){ |
| } |
| eltRefs.add(eltRef); |
| } |
| |
| property.setIsReference(true); |
| property.setXmlElementRefs(eltRefs); |
| return property; |
| } |
| |
| /** |
| * Build a reference property. |
| * |
| */ |
| private Property processReferenceProperty(Property property, TypeInfo info, JavaClass cls) { |
| |
| for (org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef nextRef : property.getXmlElementRefs()) { |
| JavaClass type = property.getType(); |
| String typeName; |
| if (helper.isCollectionType(property.getType())) { |
| if (type.hasActualTypeArguments()) { |
| type = property.getGenericType(); |
| typeName = type.getQualifiedName(); |
| } |
| } |
| |
| if (!(nextRef.getType().equals("jakarta.xml.bind.annotation.XmlElementRef.DEFAULT") || nextRef.getType().equals("jakarta.xml.bind.annotation.XmlElementRef$DEFAULT"))) { |
| typeName = nextRef.getType(); |
| type = helper.getJavaClass(typeName); |
| } |
| |
| boolean missingReference = true; |
| for (Entry<String, ElementDeclaration> entry : xmlRootElements.entrySet()) { |
| ElementDeclaration entryValue = entry.getValue(); |
| if (!(areEquals(type, Object.class)) && type.isAssignableFrom(entryValue.getJavaType())) { |
| addReferencedElement(property, entryValue); |
| missingReference = false; |
| } |
| } |
| if (missingReference) { |
| String name = nextRef.getName(); |
| String namespace = nextRef.getNamespace(); |
| if (namespace.equals(XMLProcessor.DEFAULT)) { |
| namespace = EMPTY_STRING; |
| } |
| QName qname = new QName(namespace, name); |
| JavaClass scopeClass = cls; |
| ElementDeclaration referencedElement = null; |
| while (!(scopeClass.getName().equals(JAVA_LANG_OBJECT))) { |
| Map<QName, ElementDeclaration> elements = getElementDeclarationsForScope(scopeClass.getName()); |
| if (elements != null) { |
| referencedElement = elements.get(qname); |
| } |
| if (referencedElement != null) { |
| break; |
| } |
| scopeClass = scopeClass.getSuperclass(); |
| } |
| if (referencedElement == null) { |
| referencedElement = this.getGlobalElements().get(qname); |
| } |
| if (referencedElement != null) { |
| addReferencedElement(property, referencedElement); |
| } else { |
| throw org.eclipse.persistence.exceptions.JAXBException.invalidElementRef(property.getPropertyName(), cls.getName()); |
| } |
| } |
| } |
| return property; |
| } |
| |
| private void processReferencePropertyTypes(Property property, TypeInfo info, JavaClass theClass) { |
| for (org.eclipse.persistence.jaxb.xmlmodel.XmlElementRef nextRef : property.getXmlElementRefs()) { |
| JavaClass type = property.getType(); |
| String typeName = type.getQualifiedName(); |
| if (helper.isCollectionType(property.getType())) { |
| if (type.hasActualTypeArguments()) { |
| type = property.getGenericType(); |
| typeName = type.getQualifiedName(); |
| } |
| } |
| |
| if(JAVAX_XML_BIND_JAXBELEMENT.equals(typeName)){ |
| Collection args = type.getActualTypeArguments(); |
| if(args.size() > 0){ |
| JavaClass theType = (JavaClass) args.iterator().next(); |
| processReferencedClass(theType); |
| } |
| } |
| |
| // for DEFAULT, if from XML the type will be |
| // "XmlElementRef.DEFAULT", |
| // and from annotations the value will be "XmlElementref$DEFAULT" |
| if (!(nextRef.getType().equals("jakarta.xml.bind.annotation.XmlElementRef.DEFAULT") || nextRef.getType().equals("jakarta.xml.bind.annotation.XmlElementRef$DEFAULT"))) { |
| typeName = nextRef.getType(); |
| type = helper.getJavaClass(typeName); |
| } |
| processReferencedClass(type); |
| } |
| } |
| |
| private void processPropertyAnnotations(TypeInfo info, JavaClass cls, JavaHasAnnotations propertyElement, Property property) { |
| // Check for mixed context |
| if (helper.isAnnotationPresent(propertyElement, XmlMixed.class)) { |
| info.setMixed(true); |
| property.setMixedContent(true); |
| findAndProcessObjectFactory(cls); |
| } |
| if (helper.isAnnotationPresent(propertyElement, XmlInverseReference.class)) { |
| XmlInverseReference inverseReference = (XmlInverseReference) helper.getAnnotation(propertyElement, XmlInverseReference.class); |
| property.setInverseReferencePropertyName(inverseReference.mappedBy()); |
| |
| TypeInfo targetInfo = this.getTypeInfos().get(property.getActualType().getName()); |
| if (targetInfo != null && targetInfo.getXmlAccessType() == XmlAccessType.PROPERTY) { |
| String propName = property.getPropertyName(); |
| propName = Character.toUpperCase(propName.charAt(0)) + propName.substring(1); |
| property.setInverseReferencePropertyGetMethodName(GET_STR + propName); |
| property.setInverseReferencePropertySetMethodName(SET_STR + propName); |
| } |
| |
| property.setInverseReference(true, helper.isAnnotationPresent(propertyElement, XmlElement.class)); |
| } |
| |
| processXmlJavaTypeAdapter(property, info, cls); |
| if (helper.isAnnotationPresent(propertyElement, XmlAttachmentRef.class) && areEquals(property.getActualType(), JAVAX_ACTIVATION_DATAHANDLER)) { |
| property.setIsSwaAttachmentRef(true); |
| property.setSchemaType(Constants.SWA_REF_QNAME); |
| } |
| processXmlElement(property, info); |
| |
| // JavaClass ptype = property.getActualType(); |
| if (!(property.isSwaAttachmentRef()) && isMtomAttachment(property)) { |
| property.setIsMtomAttachment(true); |
| property.setSchemaType(Constants.BASE_64_BINARY_QNAME); |
| } |
| if (helper.isAnnotationPresent(propertyElement, XmlMimeType.class)) { |
| property.setMimeType(((XmlMimeType) helper.getAnnotation(propertyElement, XmlMimeType.class)).value()); |
| } |
| // set indicator for inlining binary data - setting this to true on a |
| // non-binary data type won't have any affect |
| if (helper.isAnnotationPresent(propertyElement, XmlInlineBinaryData.class) || info.isBinaryDataToBeInlined()) { |
| property.setisInlineBinaryData(true); |
| } |
| |
| // Get schema-type info if specified and set it on the property for |
| // later use: |
| if (helper.isAnnotationPresent(propertyElement, XmlSchemaType.class)) { |
| XmlSchemaType schemaType = (XmlSchemaType) helper.getAnnotation(propertyElement, XmlSchemaType.class); |
| QName schemaTypeQname = new QName(schemaType.namespace(), schemaType.name()); |
| property.setSchemaType(schemaTypeQname); |
| } |
| |
| if (helper.isAnnotationPresent(propertyElement, XmlAttribute.class)) { |
| property.setIsAttribute(true); |
| property.setIsRequired(((XmlAttribute) helper.getAnnotation(propertyElement, XmlAttribute.class)).required()); |
| } |
| |
| if (helper.isAnnotationPresent(propertyElement, XmlAnyAttribute.class)) { |
| if (info.isSetAnyAttributePropertyName() && !info.getAnyAttributePropertyName().equals(property.getPropertyName())) { |
| throw org.eclipse.persistence.exceptions.JAXBException.multipleAnyAttributeMapping(cls.getName()); |
| } |
| if (!helper.isMapType(property.getType())) { |
| throw org.eclipse.persistence.exceptions.JAXBException.anyAttributeOnNonMap(property.getPropertyName()); |
| } |
| property.setIsAnyAttribute(true); |
| info.setAnyAttributePropertyName(property.getPropertyName()); |
| } |
| |
| // Make sure XmlElementWrapper annotation is on a collection or array |
| if (helper.isAnnotationPresent(propertyElement, XmlElementWrapper.class)) { |
| XmlElementWrapper wrapper = (XmlElementWrapper) helper.getAnnotation(propertyElement, XmlElementWrapper.class); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper xmlEltWrapper = new org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper(); |
| |
| String wrapperName = wrapper.name(); |
| if (wrapperName.equals(XMLProcessor.DEFAULT)) { |
| wrapperName = info.getXmlNameTransformer().transformElementName(property.getPropertyName()); |
| } |
| xmlEltWrapper.setName(wrapperName); |
| xmlEltWrapper.setNamespace(wrapper.namespace()); |
| xmlEltWrapper.setNillable(wrapper.nillable()); |
| xmlEltWrapper.setRequired(wrapper.required()); |
| property.setXmlElementWrapper(xmlEltWrapper); |
| } |
| |
| if (helper.isAnnotationPresent(propertyElement, XmlList.class)) { |
| // Make sure XmlList annotation is on a collection or array |
| if (!helper.isCollectionType(property.getType()) && !property.getType().isArray()) { |
| throw JAXBException.invalidList(property.getPropertyName()); |
| } |
| property.setIsXmlList(true); |
| } |
| |
| if (helper.isAnnotationPresent(propertyElement, XmlValue.class)) { |
| property.setIsXmlValue(true); |
| info.setXmlValueProperty(property); |
| } |
| |
| if (helper.isAnnotationPresent(propertyElement, XmlReadOnly.class)) { |
| property.setReadOnly(true); |
| } |
| if (helper.isAnnotationPresent(propertyElement, XmlWriteOnly.class)) { |
| property.setWriteOnly(true); |
| } |
| if (helper.isAnnotationPresent(propertyElement, XmlCDATA.class)) { |
| property.setCdata(true); |
| } |
| if (helper.isAnnotationPresent(propertyElement, XmlAccessMethods.class)) { |
| XmlAccessMethods accessMethods = (XmlAccessMethods) helper.getAnnotation(propertyElement, XmlAccessMethods.class); |
| if (!(accessMethods.getMethodName().equals(EMPTY_STRING))) { |
| property.setGetMethodName(accessMethods.getMethodName()); |
| } |
| if (!(accessMethods.setMethodName().equals(EMPTY_STRING))) { |
| property.setSetMethodName(accessMethods.setMethodName()); |
| } |
| if (!(property.isMethodProperty())) { |
| property.setMethodProperty(true); |
| } |
| } |
| |
| // handle user properties |
| if (helper.isAnnotationPresent(propertyElement, XmlProperties.class)) { |
| XmlProperties xmlProperties = (XmlProperties) helper.getAnnotation(propertyElement, XmlProperties.class); |
| Map<Object, Object> propertiesMap = createUserPropertiesMap(xmlProperties.value()); |
| property.setUserProperties(propertiesMap); |
| } else if (helper.isAnnotationPresent(propertyElement, XmlProperty.class)) { |
| XmlProperty xmlProperty = (XmlProperty) helper.getAnnotation(propertyElement, XmlProperty.class); |
| Map<Object, Object> propertiesMap = createUserPropertiesMap(new XmlProperty[] { xmlProperty }); |
| property.setUserProperties(propertiesMap); |
| } |
| // handle XmlKey |
| if (helper.isAnnotationPresent(propertyElement, XmlKey.class)) { |
| info.addXmlKeyProperty(property); |
| } |
| // handle XmlJoinNode(s) |
| processXmlJoinNodes(property); |
| processXmlNullPolicy(property, cls, info); |
| |
| // Handle XmlLocation |
| JavaHasAnnotations elem = propertyElement; |
| if (helper.isAnnotationPresent(elem, XmlLocation.class) |
| || helper.isAnnotationPresent(elem, CompilerHelper.XML_LOCATION_ANNOTATION_CLASS) |
| || helper.isAnnotationPresent(elem, CompilerHelper.OLD_XML_LOCATION_ANNOTATION_CLASS) |
| || helper.isAnnotationPresent(elem, CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_CLASS)) { |
| if (!helper.getJavaClass(Constants.LOCATOR_CLASS).isAssignableFrom(property.getType())) { |
| throw JAXBException.invalidXmlLocation(property.getPropertyName(), property.getType().getName()); |
| } |
| property.setXmlLocation(true); |
| } |
| } |
| |
| /** |
| * Process XmlJoinNode(s) for a given Property. An |
| * org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNode(s) will be |
| * created/populated using the annotation, and set on the Property for later |
| * processing. |
| * |
| * It is assumed that for a single join node XmlJoinNode will be used, and |
| * for multiple join nodes XmlJoinNodes will be used. |
| * |
| * @param property |
| * Property that may contain @XmlJoinNodes/@XmlJoinNode |
| */ |
| private void processXmlJoinNodes(Property property) { |
| List<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode> xmlJoinNodeList; |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode xmlJoinNode; |
| org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes xmlJoinNodes; |
| // handle XmlJoinNodes |
| if (helper.isAnnotationPresent(property.getElement(), XmlJoinNodes.class)) { |
| xmlJoinNodeList = new ArrayList<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode>(); |
| for (XmlJoinNode xmlJN : ((XmlJoinNodes) helper.getAnnotation(property.getElement(), XmlJoinNodes.class)).value()) { |
| xmlJoinNode = new org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode(); |
| xmlJoinNode.setXmlPath(xmlJN.xmlPath()); |
| xmlJoinNode.setReferencedXmlPath(xmlJN.referencedXmlPath()); |
| xmlJoinNodeList.add(xmlJoinNode); |
| } |
| xmlJoinNodes = new org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes(); |
| xmlJoinNodes.setXmlJoinNode(xmlJoinNodeList); |
| property.setXmlJoinNodes(xmlJoinNodes); |
| } |
| // handle XmlJoinNode |
| else if (helper.isAnnotationPresent(property.getElement(), XmlJoinNode.class)) { |
| XmlJoinNode xmlJN = (XmlJoinNode) helper.getAnnotation(property.getElement(), XmlJoinNode.class); |
| xmlJoinNode = new org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode(); |
| xmlJoinNode.setXmlPath(xmlJN.xmlPath()); |
| xmlJoinNode.setReferencedXmlPath(xmlJN.referencedXmlPath()); |
| xmlJoinNodeList = new ArrayList<org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes.XmlJoinNode>(); |
| xmlJoinNodeList.add(xmlJoinNode); |
| xmlJoinNodes = new org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes(); |
| xmlJoinNodes.setXmlJoinNode(xmlJoinNodeList); |
| property.setXmlJoinNodes(xmlJoinNodes); |
| } |
| } |
| |
| /** |
| * Responsible for validating transformer settings on a given property. |
| * Validates that for field transformers either a transformer class OR |
| * method name is set (not both) and that an xml-path is set. Validates that |
| * for attribute transformers either a transformer class OR method name is |
| * set (not both). |
| * |
| */ |
| private void validateXmlTransformationProperty(Property property) { |
| if (property.isSetXmlTransformation()) { |
| XmlTransformation xmlTransformation = property.getXmlTransformation(); |
| // validate transformer(s) |
| if (xmlTransformation.isSetXmlReadTransformer()) { |
| // validate read transformer |
| XmlReadTransformer readTransformer = xmlTransformation.getXmlReadTransformer(); |
| if (readTransformer.isSetTransformerClass()) { |
| // handle read transformer class |
| if (readTransformer.isSetMethod()) { |
| // cannot have both class and method set |
| throw JAXBException.readTransformerHasBothClassAndMethod(property.getPropertyName()); |
| } |
| } else { |
| // handle read transformer method |
| if (!readTransformer.isSetMethod()) { |
| // require class or method to be set |
| throw JAXBException.readTransformerHasNeitherClassNorMethod(property.getPropertyName()); |
| } |
| } |
| } |
| if (xmlTransformation.isSetXmlWriteTransformers()) { |
| // handle write transformer(s) |
| for (XmlWriteTransformer writeTransformer : xmlTransformation.getXmlWriteTransformer()) { |
| // must have an xml-path set |
| if (!writeTransformer.isSetXmlPath()) { |
| throw JAXBException.writeTransformerHasNoXmlPath(property.getPropertyName()); |
| } |
| if (writeTransformer.isSetTransformerClass()) { |
| // handle write transformer class |
| if (writeTransformer.isSetMethod()) { |
| // cannot have both class and method set |
| throw JAXBException.writeTransformerHasBothClassAndMethod(property.getPropertyName(), writeTransformer.getXmlPath()); |
| } |
| } else { |
| // handle write transformer method |
| if (!writeTransformer.isSetMethod()) { |
| // require class or method to be set |
| throw JAXBException.writeTransformerHasNeitherClassNorMethod(property.getPropertyName(), writeTransformer.getXmlPath()); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /** |
| * 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. |
| * |
| */ |
| protected boolean areEquals(JavaClass src, Class tgt) { |
| if (src == null || tgt == null) { |
| return false; |
| } |
| return src.getRawName().equals(tgt.getCanonicalName()); |
| } |
| |
| private void processXmlNullPolicy(Property property, JavaClass cls, TypeInfo info) { |
| if (propertyHasXmlNullPolicyAnnotation(property)) { |
| setNullPolicyOnProperty(property, helper.getAnnotation(property.getElement(), XmlNullPolicy.class)); |
| } else if (existsExternalMappingWithJavaTypeXmlNullPolicy(info)) { |
| property.setNullPolicy(info.getXmlNullPolicy()); |
| } else if (javaTypeHasXmlNullPolicyAnnotation(cls)) { |
| setNullPolicyOnProperty(property, helper.getAnnotation(cls, XmlNullPolicy.class)); |
| } else if (existsExternaMappingWithPackageXmlNullPolicy(cls)) { |
| property.setNullPolicy(packageToXmlNillableInfoMappings.get(cls.getPackageName()).getXmlNullPolicy()); |
| } else if (helper.isAnnotationPresent(cls.getPackage(), XmlNullPolicy.class)) { |
| setNullPolicyOnProperty(property, helper.getAnnotation(cls.getPackage(), XmlNullPolicy.class)); |
| } else if (helper.isAnnotationPresent(property.getElement(), XmlIsSetNullPolicy.class)) { |
| XmlIsSetNullPolicy nullPolicy = (XmlIsSetNullPolicy) helper.getAnnotation(property.getElement(), XmlIsSetNullPolicy.class); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlIsSetNullPolicy policy = new org.eclipse.persistence.jaxb.xmlmodel.XmlIsSetNullPolicy(); |
| policy.setEmptyNodeRepresentsNull(nullPolicy.emptyNodeRepresentsNull()); |
| policy.setXsiNilRepresentsNull(nullPolicy.xsiNilRepresentsNull()); |
| policy.setNullRepresentationForXml(org.eclipse.persistence.jaxb.xmlmodel.XmlMarshalNullRepresentation.valueOf(nullPolicy.nullRepresentationForXml().toString())); |
| policy.setIsSetMethodName(nullPolicy.isSetMethodName()); |
| for (XmlParameter next : nullPolicy.isSetParameters()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlIsSetNullPolicy.IsSetParameter param = new org.eclipse.persistence.jaxb.xmlmodel.XmlIsSetNullPolicy.IsSetParameter(); |
| param.setValue(next.value()); |
| param.setType(next.type().getName()); |
| policy.getIsSetParameter().add(param); |
| } |
| property.setNullPolicy(policy); |
| } |
| } |
| |
| private boolean existsExternaMappingWithPackageXmlNullPolicy(JavaClass cls) { |
| |
| if (null == packageToXmlNillableInfoMappings || !packageToXmlNillableInfoMappings.containsKey(cls.getPackageName())) { |
| return false; |
| } |
| |
| return null != packageToXmlNillableInfoMappings.get(cls.getPackageName()).getXmlNullPolicy(); |
| } |
| |
| private boolean javaTypeHasXmlNullPolicyAnnotation(JavaClass cls) { |
| return helper.isAnnotationPresent(cls, XmlNullPolicy.class); |
| } |
| |
| private boolean existsExternalMappingWithJavaTypeXmlNullPolicy(TypeInfo info) { |
| return null != info.getXmlNullPolicy(); |
| } |
| |
| private boolean propertyHasXmlNullPolicyAnnotation(Property property) { |
| return helper.isAnnotationPresent(property.getElement(), XmlNullPolicy.class); |
| } |
| |
| private void setNullPolicyOnProperty(Property property, Annotation nullPolicyAnnotation) { |
| XmlNullPolicy nullPolicy = (XmlNullPolicy) nullPolicyAnnotation; |
| org.eclipse.persistence.jaxb.xmlmodel.XmlNullPolicy policy = new org.eclipse.persistence.jaxb.xmlmodel.XmlNullPolicy(); |
| policy.setEmptyNodeRepresentsNull(nullPolicy.emptyNodeRepresentsNull()); |
| policy.setIsSetPerformedForAbsentNode(nullPolicy.isSetPerformedForAbsentNode()); |
| policy.setXsiNilRepresentsNull(nullPolicy.xsiNilRepresentsNull()); |
| policy.setNullRepresentationForXml(org.eclipse.persistence.jaxb.xmlmodel.XmlMarshalNullRepresentation.valueOf(nullPolicy.nullRepresentationForXml().toString())); |
| property.setNullPolicy(policy); |
| } |
| |
| /** |
| * 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. |
| * |
| */ |
| protected boolean areEquals(JavaClass src, String tgtCanonicalName) { |
| if (src == null || tgtCanonicalName == null) { |
| return false; |
| } |
| return src.getRawName().equals(tgtCanonicalName); |
| } |
| |
| public ArrayList<Property> getPropertyPropertiesForClass(JavaClass cls, TypeInfo info, boolean onlyPublic) { |
| return getPropertyPropertiesForClass(cls, info, onlyPublic, false); |
| } |
| |
| public ArrayList<Property> getPropertyPropertiesForClass(JavaClass cls, TypeInfo info, boolean onlyPublic, boolean onlyExplicit) { |
| ArrayList<Property> properties = new ArrayList<Property>(); |
| if (cls == null) { |
| return properties; |
| } |
| |
| // First collect all the getters and setters |
| ArrayList<JavaMethod> propertyMethods = new ArrayList<JavaMethod>(); |
| for (JavaMethod next : new ArrayList<JavaMethod>(cls.getDeclaredMethods())) { |
| if(!next.isSynthetic()){ |
| if (((next.getName().startsWith(GET_STR) && next.getName().length() > 3) || (next.getName().startsWith(IS_STR) && next.getName().length() > 2)) && next.getParameterTypes().length == 0 && next.getReturnType() != helper.getJavaClass(java.lang.Void.class)) { |
| int modifiers = next.getModifiers(); |
| |
| if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers) && ((onlyPublic && Modifier.isPublic(next.getModifiers())) || !onlyPublic || hasJAXBAnnotations(next))) { |
| propertyMethods.add(next); |
| } |
| } else if (next.getName().startsWith(SET_STR) && next.getName().length() > 3 && next.getParameterTypes().length == 1) { |
| int modifiers = next.getModifiers(); |
| if (!Modifier.isStatic(modifiers) && !Modifier.isTransient(modifiers) && ((onlyPublic && Modifier.isPublic(next.getModifiers())) || !onlyPublic || hasJAXBAnnotations(next))) { |
| propertyMethods.add(next); |
| } |
| } |
| } |
| } |
| // Next iterate over the getters and find their setter methods, add |
| // whichever one is |
| // annotated to the properties list. If neither is, use the getter |
| |
| // keep track of property names to avoid processing the same property |
| // twice (for getter and setter) |
| List<String> propertyNames = new ArrayList<String>(); |
| for (JavaMethod propertyMethod1 : propertyMethods) { |
| boolean isPropertyTransient = false; |
| JavaMethod nextMethod = propertyMethod1; |
| String propertyName = EMPTY_STRING; |
| |
| JavaMethod getMethod; |
| JavaMethod setMethod; |
| |
| JavaMethod propertyMethod = null; |
| |
| if (!nextMethod.getName().startsWith(SET_STR)) { |
| if (nextMethod.getName().startsWith(GET_STR)) { |
| propertyName = nextMethod.getName().substring(3); |
| } else if (nextMethod.getName().startsWith(IS_STR)) { |
| propertyName = nextMethod.getName().substring(2); |
| } |
| getMethod = nextMethod; |
| String setMethodName = SET_STR + propertyName; |
| |
| // use the JavaBean API to correctly decapitalize the first |
| // character, if necessary |
| propertyName = Introspector.decapitalize(propertyName); |
| |
| JavaClass[] paramTypes = { getMethod.getReturnType() }; |
| setMethod = cls.getDeclaredMethod(setMethodName, paramTypes); |
| |
| if (setMethod == null) { |
| //if there's no locally declared set method, check for an inherited |
| //set method |
| setMethod = cls.getMethod(setMethodName, paramTypes); |
| } |
| if (setMethod == null && !(hasJAXBAnnotations(getMethod))) { |
| //if there's no corresponding setter, and not explicitly |
| //annotated, don't process |
| isPropertyTransient = true; |
| } |
| |
| if (setMethod != null && hasJAXBAnnotations(setMethod)) { |
| // use the set method if it exists and is annotated |
| boolean isTransient = helper.isAnnotationPresent(setMethod, XmlTransient.class); |
| boolean isLocation = helper.isAnnotationPresent(setMethod, XmlLocation.class) || |
| helper.isAnnotationPresent(setMethod, CompilerHelper.XML_LOCATION_ANNOTATION_CLASS) || |
| helper.isAnnotationPresent(setMethod, CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_CLASS); |
| propertyMethod = setMethod; |
| if (isTransient) { |
| isPropertyTransient = true; |
| // XmlLocation can also be transient |
| if (isLocation) { |
| info.setLocationAware(true); |
| } |
| } |
| } else if ((onlyExplicit && hasJAXBAnnotations(getMethod)) || !onlyExplicit) { |
| boolean isTransient = helper.isAnnotationPresent(getMethod, XmlTransient.class); |
| boolean isLocation = helper.isAnnotationPresent(getMethod, XmlLocation.class) || |
| helper.isAnnotationPresent(setMethod, CompilerHelper.XML_LOCATION_ANNOTATION_CLASS) || |
| helper.isAnnotationPresent(setMethod, CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_CLASS); |
| propertyMethod = getMethod; |
| if (isTransient) { |
| isPropertyTransient = true; |
| // XmlLocation can also be transient |
| if (isLocation) { |
| info.setLocationAware(true); |
| } |
| } |
| } else if (onlyExplicit) { |
| continue; |
| } |
| } else { |
| propertyName = nextMethod.getName().substring(3); |
| setMethod = nextMethod; |
| |
| String getMethodName = GET_STR + propertyName; |
| |
| getMethod = cls.getDeclaredMethod(getMethodName, new JavaClass[] { }); |
| if (getMethod == null) { |
| // try is instead of get |
| getMethodName = IS_STR + propertyName; |
| getMethod = cls.getDeclaredMethod(getMethodName, new JavaClass[] { }); |
| } |
| |
| //may look for get method on parent class |
| if (getMethod == null) { |
| //look for inherited getMethod |
| getMethod = cls.getMethod(GET_STR + propertyName, new JavaClass[] { }); |
| if (getMethod == null) { |
| getMethod = cls.getMethod(IS_STR + propertyName, new JavaClass[] { }); |
| } |
| } |
| if (getMethod == null && !(hasJAXBAnnotations(setMethod))) { |
| isPropertyTransient = true; |
| } |
| if (getMethod != null && hasJAXBAnnotations(getMethod)) { |
| // use the get method if it exists and is annotated |
| boolean isTransient = helper.isAnnotationPresent(getMethod, XmlTransient.class); |
| boolean isLocation = helper.isAnnotationPresent(getMethod, XmlLocation.class) || |
| helper.isAnnotationPresent(getMethod, CompilerHelper.XML_LOCATION_ANNOTATION_CLASS) || |
| helper.isAnnotationPresent(getMethod, CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_CLASS); |
| propertyMethod = getMethod; |
| if (isTransient) { |
| isPropertyTransient = true; |
| // XmlLocation can also be transient |
| if (isLocation) { |
| info.setLocationAware(true); |
| } |
| } |
| } else if ((onlyExplicit && hasJAXBAnnotations(setMethod)) || !onlyExplicit) { |
| boolean isTransient = helper.isAnnotationPresent(setMethod, XmlTransient.class); |
| boolean isLocation = helper.isAnnotationPresent(setMethod, XmlLocation.class) || |
| helper.isAnnotationPresent(getMethod, CompilerHelper.XML_LOCATION_ANNOTATION_CLASS) || |
| helper.isAnnotationPresent(getMethod, CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_CLASS); |
| propertyMethod = setMethod; |
| if (isTransient) { |
| isPropertyTransient = true; |
| // XmlLocation can also be transient |
| if (isLocation) { |
| info.setLocationAware(true); |
| } |
| } |
| } else if (onlyExplicit) { |
| continue; |
| } |
| // use the JavaBean API to correctly decapitalize the first |
| // character, if necessary |
| propertyName = Introspector.decapitalize(propertyName); |
| } |
| |
| JavaClass ptype = null; |
| if (getMethod != null) { |
| ptype = getMethod.getReturnType(); |
| } else { |
| ptype = setMethod.getParameterTypes()[0]; |
| } |
| |
| if (!propertyNames.contains(propertyName)) { |
| try { |
| Property property = buildNewProperty(info, cls, propertyMethod, propertyName, ptype); |
| propertyNames.add(propertyName); |
| property.setTransient(isPropertyTransient); |
| |
| if (getMethod != null) { |
| property.setOriginalGetMethodName(getMethod.getName()); |
| if (property.getGetMethodName() == null) { |
| property.setGetMethodName(getMethod.getName()); |
| } |
| } |
| if (setMethod != null) { |
| property.setOriginalSetMethodName(setMethod.getName()); |
| if (property.getSetMethodName() == null) { |
| property.setSetMethodName(setMethod.getName()); |
| } |
| } |
| property.setMethodProperty(true); |
| |
| //boolean isTransient = helper.isAnnotationPresent(property.getElement(), XmlTransient.class); |
| //boolean isLocation = helper.isAnnotationPresent(property.getElement(), XmlLocation.class) || |
| // helper.isAnnotationPresent(setMethod, CompilerHelper.XML_LOCATION_ANNOTATION_CLASS) || |
| // helper.isAnnotationPresent(setMethod, CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_CLASS); |
| //if (!isTransient || (isTransient && isLocation)) { |
| properties.add(property); |
| //} |
| } catch (JAXBException ex) { |
| if (ex.getErrorCode() != JAXBException.INVALID_INTERFACE || !isPropertyTransient) { |
| throw ex; |
| } |
| } |
| } |
| } |
| |
| properties = removeSuperclassProperties(cls, properties); |
| |
| // default to alphabetical ordering |
| // RI compliancy |
| Collections.sort(properties, new PropertyComparitor()); |
| return properties; |
| } |
| |
| private ArrayList<Property> removeSuperclassProperties(JavaClass cls, ArrayList<Property> properties) { |
| ArrayList<Property> revisedProperties = new ArrayList<Property>(); |
| revisedProperties.addAll(properties); |
| |
| // Check for any get() methods that are overridden in the subclass. |
| // If we find any, remove the property, because it is already defined on |
| // the superclass. |
| JavaClass superClass = cls.getSuperclass(); |
| if (null != superClass) { |
| TypeInfo superClassInfo = typeInfos.get(superClass.getQualifiedName()); |
| if (superClassInfo != null && !superClassInfo.isTransient()) { |
| for (Property prop : properties) { |
| for (Property superProp : superClassInfo.getProperties().values()) { |
| if (superProp.getGetMethodName() != null && superProp.getGetMethodName().equals(prop.getGetMethodName()) && !superProp.isTransient()) { |
| revisedProperties.remove(prop); |
| } |
| } |
| } |
| } |
| } |
| |
| return revisedProperties; |
| } |
| |
| public ArrayList getPublicMemberPropertiesForClass(JavaClass cls, TypeInfo info) { |
| ArrayList<Property> fieldProperties = getFieldPropertiesForClass(cls, info, !hasXmlBindings()); |
| ArrayList<Property> methodProperties = getPropertyPropertiesForClass(cls, info, !hasXmlBindings()); |
| |
| // filter out non-public properties that aren't annotated |
| ArrayList<Property> publicFieldProperties = new ArrayList<Property>(); |
| ArrayList<Property> publicMethodProperties = new ArrayList<Property>(); |
| |
| for (Property next : fieldProperties) { |
| if (Modifier.isPublic(((JavaField) next.getElement()).getModifiers())) { |
| publicFieldProperties.add(next); |
| } else { |
| if (hasJAXBAnnotations(next.getElement())) { |
| publicFieldProperties.add(next); |
| } |
| } |
| } |
| |
| for (Property next : methodProperties) { |
| if (next.getElement() != null) { |
| if (Modifier.isPublic(((JavaMethod) next.getElement()).getModifiers())) { |
| publicMethodProperties.add(next); |
| } else { |
| if (hasJAXBAnnotations(next.getElement())) { |
| publicMethodProperties.add(next); |
| } |
| } |
| } |
| } |
| |
| // Not sure who should win if a property exists for both or the correct |
| // order |
| if (publicFieldProperties.size() >= 0 && publicMethodProperties.size() == 0) { |
| return publicFieldProperties; |
| } else if (publicMethodProperties.size() > 0 && publicFieldProperties.size() == 0) { |
| return publicMethodProperties; |
| } else { |
| // add any non-duplicate method properties to the collection. |
| // - in the case of a collision if one is annotated use it, |
| // otherwise |
| // use the field. |
| HashMap<String, Property> fieldPropertyMap = getPropertyMapFromArrayList(publicFieldProperties); |
| for (Property publicMethodProperty : publicMethodProperties) { |
| Property next = publicMethodProperty; |
| Property fieldProp = fieldPropertyMap.get(next.getPropertyName()); |
| if (fieldProp == null) { |
| publicFieldProperties.add(next); |
| } else if (fieldProp.isTransient()) { |
| //bug 346461 - if a public field is transient and the public methods are not |
| // then use the method |
| publicFieldProperties.remove(fieldProp); |
| publicFieldProperties.add(next); |
| } |
| } |
| return publicFieldProperties; |
| } |
| } |
| |
| public HashMap<String, Property> getPropertyMapFromArrayList(ArrayList<Property> props) { |
| HashMap propMap = new HashMap(props.size()); |
| |
| for (Object next : props) { |
| propMap.put(((Property)next).getPropertyName(), next); |
| } |
| return propMap; |
| } |
| |
| public ArrayList getNoAccessTypePropertiesForClass(JavaClass cls, TypeInfo info) { |
| ArrayList<Property> list = new ArrayList<Property>(); |
| if (cls == null) { |
| return list; |
| } |
| |
| // Iterate over the field and method properties. If ANYTHING contains an |
| // annotation and |
| // doesn't appear in the other list, add it to the final list |
| List<Property> fieldProperties = getFieldPropertiesForClass(cls, info, false); |
| Map<String, Property> fields = new HashMap<String, Property>(fieldProperties.size()); |
| for (Property next : fieldProperties) { |
| JavaHasAnnotations elem = next.getElement(); |
| if (!hasJAXBAnnotations(elem)) { |
| next.setTransient(true); |
| } |
| list.add(next); |
| fields.put(next.getPropertyName(), next); |
| } |
| |
| List<Property> methodProperties = getPropertyPropertiesForClass(cls, info, false); |
| for (Property next : methodProperties) { |
| JavaHasAnnotations elem = next.getElement(); |
| if (hasJAXBAnnotations(elem)) { |
| // If the property is annotated remove the corresponding field |
| Property fieldProperty = fields.get(next.getPropertyName()); |
| list.remove(fieldProperty); |
| list.add(next); |
| } else { |
| // If the property is not annotated only add it if there is no |
| // corresponding field. |
| next.setTransient(true); |
| if (fields.get(next.getPropertyName()) == null) { |
| list.add(next); |
| } |
| } |
| } |
| return list; |
| } |
| |
| /** |
| * Use name, namespace and type information to setup a user-defined schema |
| * type. This method will typically be called when processing an |
| * |
| * {@literal @XmlSchemaType(s)} annotation or xml-schema-type(s) metadata. |
| * |
| */ |
| public void processSchemaType(String name, String namespace, String jClassQualifiedName) { |
| this.userDefinedSchemaTypes.put(jClassQualifiedName, new QName(namespace, name)); |
| } |
| |
| public void processSchemaType(XmlSchemaType type) { |
| JavaClass jClass = helper.getJavaClass(type.type()); |
| if (jClass == null) { |
| return; |
| } |
| processSchemaType(type.name(), type.namespace(), jClass.getQualifiedName()); |
| } |
| |
| public void addEnumTypeInfo(JavaClass javaClass, EnumTypeInfo info) { |
| if (javaClass == null) { |
| return; |
| } |
| |
| info.setClassName(javaClass.getQualifiedName()); |
| Class restrictionClass = String.class; |
| QName restrictionBase = getSchemaTypeFor(helper.getJavaClass(restrictionClass)); |
| |
| if (helper.isAnnotationPresent(javaClass, XmlEnum.class)) { |
| XmlEnum xmlEnum = (XmlEnum) helper.getAnnotation(javaClass, XmlEnum.class); |
| restrictionClass = xmlEnum.value(); |
| JavaClass restrictionJavaClass= helper.getJavaClass(restrictionClass); |
| boolean restrictionIsEnum = helper.isAnnotationPresent(restrictionJavaClass, XmlEnum.class); |
| |
| if(!restrictionIsEnum){ |
| if(helper.isBuiltInJavaType(restrictionJavaClass)){ |
| restrictionBase = getSchemaTypeFor(helper.getJavaClass(restrictionClass)); |
| }else{ |
| TypeInfo restrictionInfo = typeInfos.get(restrictionJavaClass.getQualifiedName()); |
| if(restrictionInfo == null){ |
| JavaClass[] jClasses = new JavaClass[] { restrictionJavaClass }; |
| buildNewTypeInfo(jClasses); |
| restrictionInfo = typeInfos.get(restrictionJavaClass.getQualifiedName()); |
| }else if(!restrictionInfo.isPostBuilt()){ |
| postBuildTypeInfo(new JavaClass[] { restrictionJavaClass }); |
| } |
| |
| Property xmlValueProp = restrictionInfo.getXmlValueProperty(); |
| if(xmlValueProp != null){ |
| restrictionJavaClass = xmlValueProp.getActualType(); |
| restrictionBase = getSchemaTypeFor(restrictionJavaClass); |
| restrictionClass = helper.getClassForJavaClass(restrictionJavaClass); |
| } |
| } |
| }else{ |
| while (restrictionIsEnum) { |
| |
| TypeInfo restrictionTypeInfo = processReferencedClass(restrictionJavaClass); |
| restrictionBase = new QName(restrictionTypeInfo.getClassNamespace(), restrictionTypeInfo.getSchemaTypeName()); |
| |
| xmlEnum = (XmlEnum) helper.getAnnotation(restrictionJavaClass, XmlEnum.class); |
| restrictionClass = xmlEnum.value(); |
| restrictionJavaClass= helper.getJavaClass(restrictionClass); |
| restrictionIsEnum = helper.isAnnotationPresent(restrictionJavaClass, XmlEnum.class); |
| } |
| } |
| } |
| info.setRestrictionBase(restrictionBase); |
| |
| for (JavaField field : (Iterable<JavaField>) javaClass.getDeclaredFields()) { |
| if (field.isEnumConstant()) { |
| Object enumValue = field.getName(); |
| if (helper.isAnnotationPresent(field, XmlEnumValue.class)) { |
| enumValue = ((XmlEnumValue) helper.getAnnotation(field, XmlEnumValue.class)).value(); |
| } |
| if (restrictionClass != null) { |
| try { |
| enumValue = XMLConversionManager.getDefaultXMLManager().convertObject(enumValue, restrictionClass); |
| } catch (ConversionException e) { |
| throw JAXBException.invalidEnumValue(enumValue, restrictionClass.getName(), e); |
| } |
| |
| } |
| info.addJavaFieldToXmlEnumValuePair(field.getName(), enumValue); |
| } |
| } |
| // Add a non-named element declaration for each enumeration to trigger |
| // class generation |
| if(info.getXmlRootElement() == null) { |
| //process the root element and use that as the element |
| ElementDeclaration elem = new ElementDeclaration(null, javaClass, javaClass.getQualifiedName(), false); |
| this.getLocalElements().add(elem); |
| } |
| } |
| |
| public QName getSchemaTypeOrNullFor(JavaClass javaClass) { |
| if (javaClass == null) { |
| return null; |
| } |
| |
| // check user defined types first |
| QName schemaType = userDefinedSchemaTypes.get(javaClass.getQualifiedName()); |
| if (schemaType == null) { |
| schemaType = (QName) helper.getXMLToJavaTypeMap().get(javaClass.getRawName()); |
| } |
| return schemaType; |
| } |
| |
| public QName getSchemaTypeFor(JavaClass javaClass) { |
| QName schemaType = getSchemaTypeOrNullFor(javaClass); |
| if (schemaType == null) { |
| return Constants.ANY_SIMPLE_TYPE_QNAME; |
| } |
| return schemaType; |
| } |
| |
| public NamespaceInfo processNamespaceInformation(XmlSchema xmlSchema) { |
| NamespaceInfo info = new NamespaceInfo(); |
| info.setNamespaceResolver(new NamespaceResolver()); |
| String packageNamespace = null; |
| if (xmlSchema != null) { |
| String namespaceMapping = xmlSchema.namespace(); |
| if (!(namespaceMapping.equals(EMPTY_STRING) || namespaceMapping.equals(XMLProcessor.DEFAULT))) { |
| packageNamespace = namespaceMapping; |
| } else if (namespaceMapping.equals(XMLProcessor.DEFAULT)) { |
| packageNamespace = this.defaultTargetNamespace; |
| } |
| info.setNamespace(packageNamespace); |
| XmlNs[] xmlns = xmlSchema.xmlns(); |
| for (XmlNs next : xmlns) { |
| info.getNamespaceResolver().put(next.prefix(), next.namespaceURI()); |
| } |
| info.setAttributeFormQualified(xmlSchema.attributeFormDefault() == XmlNsForm.QUALIFIED); |
| info.setElementFormQualified(xmlSchema.elementFormDefault() == XmlNsForm.QUALIFIED); |
| |
| // reflectively load XmlSchema class to avoid dependency |
| try { |
| Method locationMethod = PrivilegedAccessHelper.getDeclaredMethod(XmlSchema.class, "location", new Class[] {}); |
| String location = PrivilegedAccessHelper.invokeMethod(locationMethod, xmlSchema, new Object[] {}); |
| |
| if (location != null) { |
| if (location.equals("##generate")) { |
| location = null; |
| } else if (location.equals(EMPTY_STRING)) { |
| location = null; |
| } |
| } |
| info.setLocation(location); |
| } catch (Exception ignored) { |
| // ignored |
| } |
| |
| } else { |
| info.setNamespace(defaultTargetNamespace); |
| } |
| if (!info.isElementFormQualified() ){ |
| isDefaultNamespaceAllowed = false; |
| } |
| return info; |
| } |
| |
| public Map<String, TypeInfo> getTypeInfos() { |
| return typeInfos; |
| } |
| |
| public List<JavaClass> getTypeInfoClasses() { |
| return typeInfoClasses; |
| } |
| |
| public Map<String, QName> getUserDefinedSchemaTypes() { |
| return userDefinedSchemaTypes; |
| } |
| |
| public QName getQNameForProperty(Property property, String defaultName, JavaHasAnnotations element, NamespaceInfo namespaceInfo, TypeInfo info) { |
| String uri = info.getClassNamespace(); |
| String name = XMLProcessor.DEFAULT; |
| String namespace = XMLProcessor.DEFAULT; |
| QName qName = null; |
| |
| if(property.isMap()){ |
| isDefaultNamespaceAllowed = false; |
| } |
| |
| if (helper.isAnnotationPresent(element, XmlAttribute.class)) { |
| XmlAttribute xmlAttribute = (XmlAttribute) helper.getAnnotation(element, XmlAttribute.class); |
| name = xmlAttribute.name(); |
| namespace = xmlAttribute.namespace(); |
| |
| if (name.equals(XMLProcessor.DEFAULT)) { |
| name = defaultName; |
| try { |
| name = info.getXmlNameTransformer().transformAttributeName(name); |
| } catch (Exception ex) { |
| throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(name, info.getXmlNameTransformer().getClass().getName(), ex); |
| } |
| } |
| |
| if (!namespace.equals(XMLProcessor.DEFAULT)) { |
| qName = new QName(namespace, name); |
| isDefaultNamespaceAllowed = false; |
| } else { |
| if (namespaceInfo.isAttributeFormQualified()) { |
| qName = new QName(uri, name); |
| isDefaultNamespaceAllowed = false; |
| } else { |
| qName = new QName(name); |
| } |
| } |
| } else { |
| if (helper.isAnnotationPresent(element, XmlElement.class)) { |
| XmlElement xmlElement = (XmlElement) helper.getAnnotation(element, XmlElement.class); |
| name = xmlElement.name(); |
| namespace = xmlElement.namespace(); |
| } |
| if (property.isMap() && helper.isAnnotationPresent(element, XmlElementWrapper.class)) { |
| XmlElementWrapper xmlElementWrapper = (XmlElementWrapper) helper.getAnnotation(element, XmlElementWrapper.class); |
| name = xmlElementWrapper.name(); |
| namespace = xmlElementWrapper.namespace(); |
| } |
| |
| if (name.equals(XMLProcessor.DEFAULT)) { |
| name = defaultName; |
| |
| try { |
| name = info.getXmlNameTransformer().transformElementName(name); |
| } catch (Exception ex) { |
| throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(name, info.getXmlNameTransformer().getClass().getName(), ex); |
| } |
| } |
| |
| if (!namespace.equals(XMLProcessor.DEFAULT)) { |
| qName = new QName(namespace, name); |
| if (namespace.equals(Constants.EMPTY_STRING)) { |
| isDefaultNamespaceAllowed = false; |
| } |
| } else { |
| if (namespaceInfo.isElementFormQualified()) { |
| qName = new QName(uri, name); |
| } else { |
| qName = new QName(name); |
| } |
| } |
| } |
| return qName; |
| } |
| |
| public Map<String, PackageInfo> getPackageToPackageInfoMappings() { |
| return packageToPackageInfoMappings; |
| } |
| |
| /** |
| * Add a package name/NamespaceInfo entry to the map. This method will |
| * lazy-load the map if necessary. |
| */ |
| public void addPackageToNamespaceMapping(String packageName, NamespaceInfo nsInfo) { |
| PackageInfo info = getPackageInfoWithLazyInit(packageName); |
| info.setNamespaceInfo(nsInfo); |
| } |
| |
| /** |
| * Add a package name/XmlElementNillable entry to the map. This method will |
| * lazy-load the map if necessary. |
| */ |
| public void addPackageToXmlElementNillable(String packageName, org.eclipse.persistence.jaxb.xmlmodel.XmlElementNillable xmlElementNillable) { |
| XmlNillableInfo info = getXmlNillableInfoWithLazyInit(packageName); |
| info.setXmlElementNillable(xmlElementNillable); |
| } |
| |
| /** |
| * Add a package name/XmlNullPolicy entry to the map. This method will |
| * lazy-load the map if necessary. |
| */ |
| public void addPackageToXmlNullPolicy(String packageName, org.eclipse.persistence.jaxb.xmlmodel.XmlNullPolicy xmlNullPolicy) { |
| XmlNillableInfo info = getXmlNillableInfoWithLazyInit(packageName); |
| info.setXmlNullPolicy(xmlNullPolicy); |
| } |
| |
| private XmlNillableInfo getXmlNillableInfoWithLazyInit(String packageName) { |
| if (packageToXmlNillableInfoMappings == null) { |
| packageToXmlNillableInfoMappings = new HashMap<String, XmlNillableInfo>(); |
| } |
| XmlNillableInfo info = packageToXmlNillableInfoMappings.get(packageName); |
| if (info == null) { |
| info = new XmlNillableInfo(); |
| packageToXmlNillableInfoMappings.put(packageName, info); |
| } |
| return info; |
| } |
| |
| private PackageInfo getPackageInfoWithLazyInit(String packageName) { |
| if (packageToPackageInfoMappings == null) { |
| packageToPackageInfoMappings = new HashMap<String, PackageInfo>(); |
| } |
| PackageInfo info = packageToPackageInfoMappings.get(packageName); |
| if (info == null) { |
| info = new PackageInfo(); |
| packageToPackageInfoMappings.put(packageName, info); |
| } |
| return info; |
| } |
| |
| public void addPackageToPackageInfoMapping(String packageName, PackageInfo packageInfo) { |
| if(packageToPackageInfoMappings == null) { |
| packageToPackageInfoMappings = new HashMap<String, PackageInfo>(); |
| } |
| packageToPackageInfoMappings.put(packageName, packageInfo); |
| } |
| |
| public PackageInfo getPackageInfoForPackage(JavaClass javaClass) { |
| String packageName = javaClass.getPackageName(); |
| PackageInfo packageInfo = packageToPackageInfoMappings.get(packageName); |
| if (packageInfo == null) { |
| packageInfo = getPackageInfoForPackage(javaClass.getPackage(), packageName); |
| } |
| return packageInfo; |
| } |
| |
| public PackageInfo getPackageInfoForPackage(JavaPackage pack, String packageName) { |
| PackageInfo packageInfo = packageToPackageInfoMappings.get(packageName); |
| if (packageInfo == null) { |
| XmlSchema xmlSchema = (XmlSchema) helper.getAnnotation(pack, XmlSchema.class); |
| packageInfo = new PackageInfo(); |
| NamespaceInfo namespaceInfo = processNamespaceInformation(xmlSchema); |
| |
| packageInfo.setNamespaceInfo(namespaceInfo); |
| |
| // if it's still null, generate based on package name |
| if (namespaceInfo.getNamespace() == null) { |
| namespaceInfo.setNamespace(EMPTY_STRING); |
| } |
| if (helper.isAnnotationPresent(pack, XmlAccessorType.class)) { |
| XmlAccessorType xmlAccessorType = (XmlAccessorType) helper.getAnnotation(pack, XmlAccessorType.class); |
| packageInfo.setAccessType(XmlAccessType.fromValue(xmlAccessorType.value().name())); |
| } |
| if (helper.isAnnotationPresent(pack, XmlAccessorOrder.class)) { |
| XmlAccessorOrder xmlAccessorOrder = (XmlAccessorOrder) helper.getAnnotation(pack, XmlAccessorOrder.class); |
| packageInfo.setAccessOrder(XmlAccessOrder.fromValue(xmlAccessorOrder.value().name())); |
| } |
| if (CompilerHelper.ACCESSOR_FACTORY_ANNOTATION_CLASS != null && helper.isAnnotationPresent(pack, CompilerHelper.ACCESSOR_FACTORY_ANNOTATION_CLASS)) { |
| Annotation xmlAccessorFactory = helper.getAnnotation(pack, CompilerHelper.ACCESSOR_FACTORY_ANNOTATION_CLASS); |
| Class xmlAccessorFactoryClass = null; |
| try { |
| xmlAccessorFactoryClass = PrivilegedAccessHelper.invokeMethod(CompilerHelper.ACCESSOR_FACTORY_VALUE_METHOD, xmlAccessorFactory, new Object[]{}); |
| packageInfo.setAccessorFactory(new AccessorFactoryWrapper(PrivilegedAccessHelper.newInstanceFromClass(xmlAccessorFactoryClass))); |
| } catch (Exception ex) { |
| throw JAXBException.errorInstantiatingAccessorFactory(xmlAccessorFactoryClass, ex); |
| } |
| } else if (CompilerHelper.OLD_ACCESSOR_FACTORY_ANNOTATION_CLASS != null && helper.isAnnotationPresent(pack, CompilerHelper.OLD_ACCESSOR_FACTORY_ANNOTATION_CLASS)) { |
| Annotation xmlAccessorFactory = helper.getAnnotation(pack, CompilerHelper.OLD_ACCESSOR_FACTORY_ANNOTATION_CLASS); |
| Class xmlAccessorFactoryClass = null; |
| try { |
| xmlAccessorFactoryClass = PrivilegedAccessHelper.invokeMethod(CompilerHelper.OLD_ACCESSOR_FACTORY_VALUE_METHOD, xmlAccessorFactory, new Object[]{}); |
| packageInfo.setAccessorFactory(new AccessorFactoryWrapper(PrivilegedAccessHelper.newInstanceFromClass(xmlAccessorFactoryClass))); |
| } catch (Exception ex) { |
| throw JAXBException.errorInstantiatingAccessorFactory(xmlAccessorFactoryClass, ex); |
| } |
| } else if (CompilerHelper.INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS != null && helper.isAnnotationPresent(pack, CompilerHelper.INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS)) { |
| Annotation xmlAccessorFactory = helper.getAnnotation(pack, CompilerHelper.INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS); |
| Class xmlAccessorFactoryClass = null; |
| try { |
| xmlAccessorFactoryClass = PrivilegedAccessHelper.invokeMethod(CompilerHelper.INTERNAL_ACCESSOR_FACTORY_VALUE_METHOD, xmlAccessorFactory, new Object[]{}); |
| packageInfo.setAccessorFactory(new AccessorFactoryWrapper(PrivilegedAccessHelper.newInstanceFromClass(xmlAccessorFactoryClass))); |
| } catch (Exception ex) { |
| throw JAXBException.errorInstantiatingAccessorFactory(xmlAccessorFactoryClass, ex); |
| } |
| } |
| packageToPackageInfoMappings.put(packageName, packageInfo); |
| } |
| return packageInfo; |
| } |
| |
| public NamespaceInfo findInfoForNamespace(String namespace) { |
| for(PackageInfo next:this.packageToPackageInfoMappings.values()) { |
| String nextUri = next.getNamespace(); |
| if(nextUri == null) { |
| nextUri = Constants.EMPTY_STRING; |
| } |
| if(namespace == null) { |
| namespace = Constants.EMPTY_STRING; |
| } |
| |
| if(nextUri.equals(namespace)) { |
| return next.getNamespaceInfo(); |
| } |
| } |
| return null; |
| } |
| |
| void checkForCallbackMethods() { |
| JavaClass unmarshallerCls = helper.getJavaClass(Unmarshaller.class); |
| JavaClass marshallerCls = helper.getJavaClass(Marshaller.class); |
| JavaClass objectCls = helper.getJavaClass(Object.class); |
| JavaClass[] unmarshalParams = new JavaClass[] { unmarshallerCls, objectCls }; |
| JavaClass[] marshalParams = new JavaClass[] { marshallerCls }; |
| |
| for (JavaClass next : typeInfoClasses) { |
| if (next == null) { |
| continue; |
| } |
| |
| UnmarshalCallback unmarshalCallback = null; |
| MarshalCallback marshalCallback = null; |
| // look for before unmarshal callback |
| if (next.getMethod("beforeUnmarshal", unmarshalParams) != null) { |
| unmarshalCallback = new UnmarshalCallback(); |
| unmarshalCallback.setDomainClassName(next.getQualifiedName()); |
| unmarshalCallback.setHasBeforeUnmarshalCallback(); |
| } |
| // look for after unmarshal callback |
| if (next.getMethod("afterUnmarshal", unmarshalParams) != null) { |
| if (unmarshalCallback == null) { |
| unmarshalCallback = new UnmarshalCallback(); |
| unmarshalCallback.setDomainClassName(next.getQualifiedName()); |
| } |
| unmarshalCallback.setHasAfterUnmarshalCallback(); |
| } |
| // if before/after unmarshal callback was found, add the callback to |
| // the list |
| if (unmarshalCallback != null) { |
| if (this.unmarshalCallbacks == null) { |
| this.unmarshalCallbacks = new HashMap<String, UnmarshalCallback>(); |
| } |
| unmarshalCallbacks.put(next.getQualifiedName(), unmarshalCallback); |
| } |
| // look for before marshal callback |
| if (next.getMethod("beforeMarshal", marshalParams) != null) { |
| marshalCallback = new MarshalCallback(); |
| marshalCallback.setDomainClassName(next.getQualifiedName()); |
| marshalCallback.setHasBeforeMarshalCallback(); |
| } |
| // look for after marshal callback |
| if (next.getMethod("afterMarshal", marshalParams) != null) { |
| if (marshalCallback == null) { |
| marshalCallback = new MarshalCallback(); |
| marshalCallback.setDomainClassName(next.getQualifiedName()); |
| } |
| marshalCallback.setHasAfterMarshalCallback(); |
| } |
| // if before/after marshal callback was found, add the callback to |
| // the list |
| if (marshalCallback != null) { |
| if (this.marshalCallbacks == null) { |
| this.marshalCallbacks = new HashMap<String, MarshalCallback>(); |
| } |
| marshalCallbacks.put(next.getQualifiedName(), marshalCallback); |
| } |
| } |
| } |
| |
| public Map<String, MarshalCallback> getMarshalCallbacks() { |
| return this.marshalCallbacks; |
| } |
| |
| public Map<String, UnmarshalCallback> getUnmarshalCallbacks() { |
| return this.unmarshalCallbacks; |
| } |
| |
| private void findAndProcessObjectFactory(JavaClass cls){ |
| //need to make sure objectfactory gets processed. |
| try { |
| String className =cls.getPackageName() + ".ObjectFactory"; |
| findAndProcessObjectFactory(className); |
| } catch (JAXBException ignored) { /* ignored */} |
| } |
| |
| void findAndProcessObjectFactory(String objectFactoryClassName){ |
| //need to make sure objectfactory gets processed. |
| try { |
| if(objectFactoryClassNames.contains(objectFactoryClassName)){ |
| return; |
| } |
| JavaClass javaClass = helper.getJavaClass(objectFactoryClassName); |
| if (isXmlRegistry(javaClass)) { |
| JavaClass[] processed = this.processObjectFactory(javaClass, new ArrayList<JavaClass>()); |
| preBuildTypeInfo(processed); |
| buildTypeInfo(processed); |
| updateGlobalElements(processed); |
| } |
| } catch (JAXBException ignored){ /* ignored */ } |
| } |
| |
| public JavaClass[] processObjectFactory(JavaClass objectFactoryClass, List<JavaClass> classes) { |
| |
| String className = objectFactoryClass.getName(); |
| if(objectFactoryClassNames.contains(className)){ |
| return new JavaClass[0]; |
| } |
| objectFactoryClassNames.add(className); |
| // if there is an xml-registry from XML for this JavaClass, create a map |
| // of method names to XmlElementDecl objects to simplify processing |
| // later on in this method |
| Map<String, org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry.XmlElementDecl> elemDecls = new HashMap<String, org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry.XmlElementDecl>(); |
| org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry xmlReg = xmlRegistries.get(objectFactoryClass.getQualifiedName()); |
| if (xmlReg != null) { |
| // process xml-element-decl entries |
| for (org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry.XmlElementDecl xmlElementDecl : xmlReg.getXmlElementDecl()) { |
| // key each element-decl on method name |
| elemDecls.put(xmlElementDecl.getJavaMethod(), xmlElementDecl); |
| } |
| } |
| |
| Collection methods = objectFactoryClass.getDeclaredMethods(); |
| Iterator methodsIter = methods.iterator(); |
| PackageInfo packageInfo = getPackageInfoForPackage(objectFactoryClass); |
| while (methodsIter.hasNext()) { |
| JavaMethod next = (JavaMethod) methodsIter.next(); |
| if (next.getName().startsWith(CREATE)) { |
| JavaClass type = next.getReturnType(); |
| if (JAVAX_XML_BIND_JAXBELEMENT.equals(type.getName())) { |
| Object[] actualTypeArguments = type.getActualTypeArguments().toArray(); |
| if (actualTypeArguments.length == 0) { |
| type = helper.getObjectClass(); |
| } else { |
| type = (JavaClass) actualTypeArguments[0]; |
| } |
| type = processXmlElementDecl(type, next, packageInfo, elemDecls); |
| }else if (helper.getJaxbElementClass().isAssignableFrom(type)) { |
| this.factoryMethods.put(type.getRawName(), next); |
| type = processXmlElementDecl(type, next, packageInfo, elemDecls); |
| } else { |
| this.factoryMethods.put(type.getRawName(), next); |
| } |
| if (!helper.isBuiltInJavaType(type) && !helper.classExistsInArray(type, classes)) { |
| classes.add(type); |
| } |
| } |
| } |
| |
| if (classes.size() > 0) { |
| classesToProcessPropertyTypes.addAll(classes); |
| return classes.toArray(new JavaClass[classes.size()]); |
| } else { |
| return new JavaClass[0]; |
| } |
| } |
| |
| private JavaClass processXmlElementDecl(JavaClass type, JavaMethod next, PackageInfo packageInfo, Map<String, org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry.XmlElementDecl> elemDecls){ |
| JavaClass returnType = type; |
| // if there's an XmlElementDecl for this method from XML, use it |
| // - otherwise look for an annotation |
| org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry.XmlElementDecl xmlEltDecl = elemDecls.get(next.getName()); |
| if (( xmlEltDecl != null) || helper.isAnnotationPresent(next, XmlElementDecl.class)) { |
| QName qname; |
| QName substitutionHead = null; |
| String url; |
| String localName; |
| String defaultValue = null; |
| Class scopeClass = jakarta.xml.bind.annotation.XmlElementDecl.GLOBAL.class; |
| |
| if (xmlEltDecl != null) { |
| url = xmlEltDecl.getNamespace(); |
| localName = xmlEltDecl.getName(); |
| String scopeClassName = xmlEltDecl.getScope(); |
| if (!scopeClassName.equals(ELEMENT_DECL_GLOBAL)) { |
| JavaClass jScopeClass = helper.getJavaClass(scopeClassName); |
| if (jScopeClass != null) { |
| scopeClass = helper.getClassForJavaClass(jScopeClass); |
| if (scopeClass == null) { |
| scopeClass = jakarta.xml.bind.annotation.XmlElementDecl.GLOBAL.class; |
| } |
| } |
| } |
| if (!xmlEltDecl.getSubstitutionHeadName().equals(EMPTY_STRING)) { |
| String subHeadLocal = xmlEltDecl.getSubstitutionHeadName(); |
| String subHeadNamespace = xmlEltDecl.getSubstitutionHeadNamespace(); |
| if (subHeadNamespace.equals(XMLProcessor.DEFAULT)) { |
| subHeadNamespace = packageInfo.getNamespace(); |
| } |
| substitutionHead = new QName(subHeadNamespace, subHeadLocal); |
| } |
| if (!(xmlEltDecl.getDefaultValue().length() == 1 && xmlEltDecl.getDefaultValue().startsWith(ELEMENT_DECL_DEFAULT))) { |
| defaultValue = xmlEltDecl.getDefaultValue(); |
| } |
| } else { |
| // there was no xml-element-decl for this method in XML, |
| // so use the annotation |
| XmlElementDecl elementDecl = (XmlElementDecl) helper.getAnnotation(next, XmlElementDecl.class); |
| url = elementDecl.namespace(); |
| localName = elementDecl.name(); |
| scopeClass = elementDecl.scope(); |
| if (!elementDecl.substitutionHeadName().equals(EMPTY_STRING)) { |
| String subHeadLocal = elementDecl.substitutionHeadName(); |
| String subHeadNamespace = elementDecl.substitutionHeadNamespace(); |
| if (subHeadNamespace.equals(XMLProcessor.DEFAULT)) { |
| subHeadNamespace = packageInfo.getNamespace(); |
| } |
| |
| substitutionHead = new QName(subHeadNamespace, subHeadLocal); |
| } |
| if (!(elementDecl.defaultValue().length() == 1 && elementDecl.defaultValue().startsWith(ELEMENT_DECL_DEFAULT))) { |
| defaultValue = elementDecl.defaultValue(); |
| } |
| } |
| |
| if (XMLProcessor.DEFAULT.equals(url)) { |
| url = packageInfo.getNamespace(); |
| } |
| if(Constants.EMPTY_STRING.equals(url)) { |
| isDefaultNamespaceAllowed = false; |
| qname = new QName(localName); |
| }else{ |
| qname = new QName(url, localName); |
| } |
| |
| boolean isList = false; |
| if (JAVA_UTIL_LIST.equals(type.getName())) { |
| isList = true; |
| Collection args = type.getActualTypeArguments(); |
| if (args.size() > 0) { |
| type = (JavaClass) args.iterator().next(); |
| } |
| } |
| |
| ElementDeclaration declaration = new ElementDeclaration(qname, type, type.getQualifiedName(), isList, scopeClass); |
| if (substitutionHead != null) { |
| declaration.setSubstitutionHead(substitutionHead); |
| } |
| if (defaultValue != null) { |
| declaration.setDefaultValue(defaultValue); |
| } |
| |
| if (helper.isAnnotationPresent(next, XmlJavaTypeAdapter.class)) { |
| XmlJavaTypeAdapter typeAdapter = (XmlJavaTypeAdapter) helper.getAnnotation(next, XmlJavaTypeAdapter.class); |
| Class typeAdapterClass = typeAdapter.value(); |
| declaration.setJavaTypeAdapterClass(typeAdapterClass); |
| |
| Class declJavaType = CompilerHelper.getTypeFromAdapterClass(typeAdapterClass); |
| JavaClass adaptedType = helper.getJavaClass(declJavaType); |
| declaration.setJavaType(adaptedType); |
| declaration.setAdaptedJavaType(type); |
| returnType = adaptedType; |
| } |
| if (helper.isAnnotationPresent(next, XmlMimeType.class)) { |
| XmlMimeType mimeType = (XmlMimeType)helper.getAnnotation(next, XmlMimeType.class); |
| declaration.setXmlMimeType(mimeType.value()); |
| } |
| if (helper.isAnnotationPresent(next, XmlAttachmentRef.class)) { |
| declaration.setXmlAttachmentRef(true); |
| } |
| Map<QName, ElementDeclaration> elements = getElementDeclarationsForScope(scopeClass.getName()); |
| if (elements == null) { |
| elements = new HashMap<QName, ElementDeclaration>(); |
| this.elementDeclarations.put(scopeClass.getName(), elements); |
| } |
| if(elements.containsKey(qname)){ |
| throw JAXBException.duplicateElementName(qname); |
| } |
| |
| elements.put(qname, declaration); |
| } |
| return returnType; |
| } |
| |
| /** |
| * Lazy load and return the map of global elements. |
| * |
| */ |
| public Map<QName, ElementDeclaration> getGlobalElements() { |
| return this.elementDeclarations.get(XmlElementDecl.GLOBAL.class.getName()); |
| } |
| |
| public void updateGlobalElements(JavaClass[] classesToProcess) { |
| // Once all the global element declarations have been created, make sure |
| // that any ones that have |
| // a substitution head set are added to the list of substitutable |
| // elements on the declaration for that |
| // head. |
| |
| // Look for XmlRootElement declarations |
| for (JavaClass javaClass : classesToProcess) { |
| TypeInfo info = typeInfos.get(javaClass.getQualifiedName()); |
| if (info == null) { |
| continue; |
| } |
| if (!info.isTransient() && info.isSetXmlRootElement()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement xmlRE = info.getXmlRootElement(); |
| NamespaceInfo namespaceInfo; |
| namespaceInfo = getPackageInfoForPackage(javaClass).getNamespaceInfo(); |
| |
| String elementName = xmlRE.getName(); |
| if (elementName.equals(XMLProcessor.DEFAULT) || elementName.equals(EMPTY_STRING)) { |
| XMLNameTransformer transformer = info.getXmlNameTransformer(); |
| try { |
| elementName = transformer.transformRootElementName(javaClass.getName()); |
| } catch (Exception ex) { |
| throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex); |
| } |
| |
| } |
| String rootNamespace = xmlRE.getNamespace(); |
| QName rootElemName = null; |
| if (rootNamespace.equals(XMLProcessor.DEFAULT)) { |
| if (namespaceInfo == null) { |
| rootElemName = new QName(elementName); |
| } else { |
| String rootNS = namespaceInfo.getNamespace(); |
| rootElemName = new QName(rootNS, elementName); |
| if (rootNS.equals(Constants.EMPTY_STRING)) { |
| isDefaultNamespaceAllowed = false; |
| } |
| } |
| } else { |
| rootElemName = new QName(rootNamespace, elementName); |
| if (rootNamespace.equals(Constants.EMPTY_STRING)) { |
| isDefaultNamespaceAllowed = false; |
| } |
| } |
| ElementDeclaration declaration = new ElementDeclaration(rootElemName, javaClass, javaClass.getQualifiedName(), false); |
| declaration.setIsXmlRootElement(true); |
| addGlobalElement(rootElemName, declaration); |
| this.xmlRootElements.put(javaClass.getQualifiedName(), declaration); |
| } |
| } |
| |
| for (QName next : this.getGlobalElements().keySet()) { |
| ElementDeclaration nextDeclaration = this.getGlobalElements().get(next); |
| QName substitutionHead = nextDeclaration.getSubstitutionHead(); |
| while (substitutionHead != null) { |
| ElementDeclaration rootDeclaration = this.getGlobalElements().get(substitutionHead); |
| rootDeclaration.addSubstitutableElement(nextDeclaration); |
| if (rootDeclaration.getSubstitutionHead() != null && rootDeclaration.getSubstitutionHead().equals(substitutionHead)) { |
| // Break the loop if substitutionHead equals rootDeclaration's substitutionHead |
| // (XmlElementDecl's substitutionHeadName == name) |
| substitutionHead = null; |
| } else { |
| substitutionHead = rootDeclaration.getSubstitutionHead(); |
| } |
| } |
| } |
| } |
| |
| private void addReferencedElement(Property property, ElementDeclaration referencedElement) { |
| property.addReferencedElement(referencedElement); |
| if (referencedElement.getSubstitutableElements() != null && referencedElement.getSubstitutableElements().size() > 0) { |
| for (ElementDeclaration substitutable : referencedElement.getSubstitutableElements()) { |
| if (substitutable != referencedElement) { |
| addReferencedElement(property, substitutable); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns true if the field or method passed in is annotated with JAXB |
| * annotations. |
| */ |
| private boolean hasJAXBAnnotations(JavaHasAnnotations elem) { |
| if(elem == null){ |
| return false; |
| } |
| List annotations = (List<JavaAnnotation>) elem.getAnnotations(); |
| if (annotations == null || annotations.isEmpty()) { |
| return false; |
| } |
| for (Object annotation : annotations) { |
| String nextName = ((JavaAnnotation) annotation).getName(); |
| if (nextName.startsWith(JAVAX_XML_BIND_ANNOTATION) |
| || nextName.startsWith(OXM_ANNOTATIONS) |
| || nextName.equals(CompilerHelper.XML_LOCATION_ANNOTATION_NAME) |
| || nextName.equals(CompilerHelper.INTERNAL_XML_LOCATION_ANNOTATION_NAME)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| private void validatePropOrderForInfo(TypeInfo info) { |
| if (info.isTransient()) { |
| return; |
| } |
| if(info.getXmlVirtualAccessMethods() != null) { |
| return; |
| } |
| // Ensure that all properties in the propOrder list actually exist |
| String[] propOrder = info.getPropOrder(); |
| int propOrderLength = propOrder.length; |
| if (propOrderLength > 0) { |
| for (int i = 1; i < propOrderLength; i++) { |
| String nextPropName = propOrder[i]; |
| if (!nextPropName.equals(EMPTY_STRING) && !info.getPropertyNames().contains(nextPropName)) { |
| throw JAXBException.nonExistentPropertyInPropOrder(nextPropName, info.getJavaClassName()); |
| } |
| } |
| } |
| } |
| |
| private void validateXmlValueFieldOrProperty(JavaClass cls, Property property) { |
| JavaClass ptype = property.getActualType(); |
| String propName = property.getPropertyName(); |
| JavaClass parent = cls.getSuperclass(); |
| |
| while (parent != null && !(parent.getQualifiedName().equals(JAVA_LANG_OBJECT))) { |
| if (!useXmlValueExtension(property)) { |
| throw JAXBException.propertyOrFieldCannotBeXmlValue(propName, cls.getQualifiedName()); |
| } else { |
| TypeInfo parentTypeInfo = typeInfos.get(parent.getQualifiedName()); |
| if(hasElementMappedProperties(parentTypeInfo)) { |
| throw JAXBException.propertyOrFieldCannotBeXmlValue(propName, cls.getQualifiedName()); |
| } |
| parent = parent.getSuperclass(); |
| } |
| } |
| |
| QName schemaQName = getSchemaTypeOrNullFor(ptype); |
| if (schemaQName == null) { |
| TypeInfo refInfo = processReferencedClass(ptype); |
| if (refInfo != null && !refInfo.isEnumerationType() && refInfo.getXmlValueProperty() == null) { |
| throw JAXBException.invalidTypeForXmlValueField(propName, cls.getQualifiedName()); |
| } |
| } |
| } |
| |
| private boolean useXmlValueExtension(Property property) { |
| return MOXySystemProperties.xmlValueExtension || helper.isAnnotationPresent(property.getElement(), XmlValueExtension.class) || property.isXmlValueExtension(); |
| } |
| |
| private boolean hasElementMappedProperties(TypeInfo typeInfo) { |
| for(Property property : typeInfo.getPropertyList()) { |
| if(!(property.isTransient()|| property.isAttribute() || property.isAnyAttribute())) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| private void validateXmlAttributeFieldOrProperty(TypeInfo tInfo, Property property) { |
| // Check that @XmlAttribute references a Java type that maps to text in XML |
| JavaClass ptype = property.getActualType(); |
| TypeInfo refInfo = typeInfos.get(ptype.getQualifiedName()); |
| if (refInfo != null) { |
| if (!refInfo.isPostBuilt()) { |
| postBuildTypeInfo(new JavaClass[] { ptype }); |
| } |
| if (!refInfo.isEnumerationType()) { |
| JavaClass parent = ptype.getSuperclass(); |
| boolean hasMapped = false; |
| while (parent != null) { |
| hasMapped = hasTextMapping(refInfo); |
| if (hasMapped || parent.getQualifiedName().equals(JAVA_LANG_OBJECT)) { |
| break; |
| } |
| refInfo = typeInfos.get(parent.getQualifiedName()); |
| parent = parent.getSuperclass(); |
| } |
| if (!hasMapped) { |
| String propName = property.getPropertyName(); |
| String typeName = tInfo.getJavaClassName(); |
| String refTypeName = refInfo.getJavaClassName(); |
| throw org.eclipse.persistence.exceptions.JAXBException.mustMapToText(propName, typeName, refTypeName); |
| } |
| } |
| } |
| } |
| |
| private boolean hasTextMapping(TypeInfo tInfo) { |
| Collection<Property> props = tInfo.getProperties().values(); |
| for (Property property : props) { |
| if (property.isAttribute()) { |
| JavaClass ptype = property.getActualType(); |
| TypeInfo refInfo = typeInfos.get(ptype.getQualifiedName()); |
| if (refInfo != null && refInfo != tInfo) { |
| return hasTextMapping(refInfo); |
| } |
| } |
| } |
| |
| boolean hasXmlId = (tInfo.getIDProperty() != null && !tInfo.getIDProperty().isTransient()); |
| boolean hasXmlValue = (tInfo.getXmlValueProperty() != null && !tInfo.getXmlValueProperty().isTransient()); |
| if (hasXmlValue) { |
| // Ensure there is an @XmlValue property and nothing else |
| hasXmlValue = CompilerHelper.isSimpleType(tInfo); |
| } |
| |
| return (hasXmlValue || hasXmlId); |
| } |
| |
| private Class generateWrapperForMapClass(JavaClass mapClass, JavaClass keyClass, JavaClass valueClass, TypeMappingInfo typeMappingInfo) { |
| String packageName = JAXB_DEV; |
| NamespaceResolver combinedNamespaceResolver = new NamespaceResolver(); |
| if (!helper.isBuiltInJavaType(keyClass)) { |
| String keyPackageName = keyClass.getPackageName(); |
| packageName = packageName + DOT_CHR + keyPackageName; |
| NamespaceInfo keyNamespaceInfo = getPackageInfoForPackage(keyClass).getNamespaceInfo(); |
| if (keyNamespaceInfo != null) { |
| java.util.Vector<Namespace> namespaces = keyNamespaceInfo.getNamespaceResolver().getNamespaces(); |
| for (Namespace n : namespaces) { |
| combinedNamespaceResolver.put(n.getPrefix(), n.getNamespaceURI()); |
| } |
| |
| } |
| } |
| |
| if (!helper.isBuiltInJavaType(valueClass)) { |
| String valuePackageName = valueClass.getPackageName(); |
| packageName = packageName + DOT_CHR + valuePackageName; |
| NamespaceInfo valueNamespaceInfo = getPackageInfoForPackage(valueClass).getNamespaceInfo(); |
| if (valueNamespaceInfo != null) { |
| java.util.Vector<Namespace> namespaces = valueNamespaceInfo.getNamespaceResolver().getNamespaces(); |
| for (Namespace n : namespaces) { |
| combinedNamespaceResolver.put(n.getPrefix(), n.getNamespaceURI()); |
| } |
| } |
| } |
| String namespace = this.defaultTargetNamespace; |
| if (namespace == null) { |
| namespace = EMPTY_STRING; |
| } |
| PackageInfo packageInfo = packageToPackageInfoMappings.get(mapClass.getPackageName()); |
| if (packageInfo == null) { |
| packageInfo = getPackageToPackageInfoMappings().get(packageName); |
| } else { |
| if (packageInfo.getNamespace() != null) { |
| namespace = packageInfo.getNamespace(); |
| } |
| getPackageToPackageInfoMappings().put(packageName, packageInfo); |
| } |
| if (packageInfo == null) { |
| packageInfo = new PackageInfo(); |
| packageInfo.setNamespaceInfo(new NamespaceInfo()); |
| packageInfo.setNamespace(namespace); |
| packageInfo.setNamespaceResolver(combinedNamespaceResolver); |
| |
| getPackageToPackageInfoMappings().put(packageName, packageInfo); |
| } |
| |
| int beginIndex = keyClass.getName().lastIndexOf(DOT_CHR) + 1; |
| String keyName = keyClass.getName().substring(beginIndex); |
| int dollarIndex = keyName.indexOf(DOLLAR_SIGN_CHR); |
| if (dollarIndex > -1) { |
| keyName = keyName.substring(dollarIndex + 1); |
| } |
| |
| beginIndex = valueClass.getName().lastIndexOf(DOT_CHR) + 1; |
| String valueName = valueClass.getName().substring(beginIndex); |
| dollarIndex = valueName.indexOf(DOLLAR_SIGN_CHR); |
| if (dollarIndex > -1) { |
| valueName = valueName.substring(dollarIndex + 1); |
| } |
| String collectionClassShortName = mapClass.getRawName().substring(mapClass.getRawName().lastIndexOf(DOT_CHR) + 1); |
| String suggestedClassName = keyName + valueName + collectionClassShortName; |
| |
| String qualifiedClassName = packageName + DOT_CHR + suggestedClassName; |
| qualifiedClassName = getNextAvailableClassName(qualifiedClassName); |
| |
| String qualifiedInternalClassName = qualifiedClassName.replace(DOT_CHR, SLASH_CHR); |
| String internalKeyName = keyClass.getQualifiedName().replace(DOT_CHR, SLASH_CHR); |
| String internalValueName = valueClass.getQualifiedName().replace(DOT_CHR, SLASH_CHR); |
| |
| Type mapType = Type.getType(L + mapClass.getRawName().replace(DOT_CHR, SLASH_CHR) + SEMI_COLON); |
| |
| EclipseLinkASMClassWriter cw = new EclipseLinkASMClassWriter(); |
| |
| String sig = "Lorg/eclipse/persistence/internal/jaxb/many/MapValue<L" + mapType.getInternalName() + "<L" + internalKeyName + ";L" + internalValueName + ";>;>;"; |
| cw.visit(Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, qualifiedInternalClassName, sig, "org/eclipse/persistence/internal/jaxb/many/MapValue", null); |
| |
| // Write Field: @... public Map entry |
| String fieldSig = L + mapType.getInternalName() + "<L" + internalKeyName + ";L" + internalValueName + ";>;"; |
| FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC, "entry", L + mapType.getInternalName() + SEMI_COLON, fieldSig, null); |
| fv.visitAnnotation(Type.getDescriptor(XmlElement.class), true); |
| if (typeMappingInfo != null) { |
| Annotation[] annotations = typeMappingInfo.getAnnotations(); |
| if (annotations != null) { |
| for (Annotation nextAnnotation : annotations) { |
| if (nextAnnotation != null && !(nextAnnotation instanceof XmlElement) && !(nextAnnotation instanceof XmlJavaTypeAdapter)) { |
| String annotationClassName = nextAnnotation.annotationType().getName(); |
| AnnotationVisitor av = fv.visitAnnotation(L + annotationClassName.replace(DOT_CHR, SLASH_CHR) + SEMI_COLON, true); |
| for (Method next : nextAnnotation.annotationType().getDeclaredMethods()) { |
| try { |
| Object nextValue = next.invoke(nextAnnotation, new Object[] { }); |
| if (nextValue instanceof Class) { |
| Type nextType = Type.getType(L + ((Class) nextValue).getName().replace(DOT_CHR, SLASH_CHR) + SEMI_COLON); |
| nextValue = nextType; |
| } |
| av.visit(next.getName(), nextValue); |
| } catch (InvocationTargetException ignored) { |
| // ignore the invocation target exception here. |
| } catch (IllegalAccessException ignored) { |
| // ignore the illegal access exception here. |
| } |
| } |
| av.visitEnd(); |
| } |
| } |
| } |
| } |
| fv.visitEnd(); |
| |
| MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "org/eclipse/persistence/internal/jaxb/many/MapValue", "<init>", "()V", false); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| |
| // Write: @XmlTransient public void setItem(???) |
| String methodSig = "(L" + mapType.getInternalName() + "<L" + internalKeyName + ";L" + internalValueName + ";>;)V"; |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setItem", "(L" + mapType.getInternalName() + ";)V", methodSig, null); |
| // TODO: Verify that we really want to put @XmlTranient on setItem |
| // method |
| mv.visitAnnotation("Ljakarta/xml/bind/annotation/XmlTransient;", true); |
| Label l0 = new Label(); |
| mv.visitLabel(l0); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitVarInsn(Opcodes.ALOAD, 1); |
| mv.visitFieldInsn(Opcodes.PUTFIELD, qualifiedInternalClassName, "entry", L + mapType.getInternalName() + SEMI_COLON); |
| mv.visitInsn(Opcodes.RETURN); |
| Label l1 = new Label(); |
| mv.visitLabel(l1); |
| |
| // Replacement?:LocalVariableTypeTableAttribute cvAttr = new |
| // LocalVariableTypeTableAttribute(); |
| // mv.visitAttribute(cvAttr); |
| |
| mv.visitMaxs(2, 2); |
| mv.visitEnd(); |
| |
| // Write @XmlTransient public ??? getItem() |
| methodSig = "()L" + mapType.getInternalName() + "<L" + internalKeyName + ";L" + internalValueName + ";>;"; |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getItem", "()L" + mapType.getInternalName() + SEMI_COLON, methodSig, null); |
| mv.visitAnnotation("Ljakarta/xml/bind/annotation/XmlTransient;", true); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitFieldInsn(Opcodes.GETFIELD, qualifiedInternalClassName, "entry", L + mapType.getInternalName() + SEMI_COLON); |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "getItem", "()Ljava/lang/Object;", null, null); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "getItem", "()L" + mapType.getInternalName() + SEMI_COLON, false); |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC + Opcodes.ACC_BRIDGE + Opcodes.ACC_SYNTHETIC, "setItem", "(Ljava/lang/Object;)V", null, null); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitVarInsn(Opcodes.ALOAD, 1); |
| mv.visitTypeInsn(Opcodes.CHECKCAST, mapType.getInternalName()); |
| mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, qualifiedInternalClassName, "setItem", "(L" + mapType.getInternalName() + ";)V", false); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(2, 2); |
| mv.visitEnd(); |
| |
| // Write @XmlType(namespace) |
| AnnotationVisitor av = cw.visitAnnotation("Ljakarta/xml/bind/annotation/XmlType;", true); |
| av.visit("namespace", namespace); |
| |
| cw.visitEnd(); |
| |
| byte[] classBytes = cw.toByteArray(); |
| return generateClassFromBytes(qualifiedClassName, classBytes); |
| } |
| |
| private Class generateWrapperForArrayClass(JavaClass arrayClass, TypeMappingInfo typeMappingInfo, Class xmlElementType, List<JavaClass> classesToProcess) { |
| JavaClass componentClass = null; |
| if (typeMappingInfo != null && xmlElementType != null) { |
| componentClass = helper.getJavaClass(xmlElementType); |
| } else { |
| componentClass = arrayClass.getComponentType(); |
| } |
| if (componentClass.isArray()) { |
| Class nestedArrayClass = arrayClassesToGeneratedClasses.get(componentClass.getName()); |
| if (nestedArrayClass == null) { |
| nestedArrayClass = generateWrapperForArrayClass(componentClass, typeMappingInfo, xmlElementType, classesToProcess); |
| arrayClassesToGeneratedClasses.put(componentClass.getName(), nestedArrayClass); |
| classesToProcess.add(helper.getJavaClass(nestedArrayClass)); |
| } |
| return generateArrayValue(arrayClass, helper.getJavaClass(nestedArrayClass), helper.getJavaClass(nestedArrayClass), typeMappingInfo); |
| } else { |
| return generateArrayValue(arrayClass, componentClass, componentClass, typeMappingInfo); |
| } |
| } |
| |
| private Class generateArrayValue(JavaClass arrayClass, JavaClass componentClass, JavaClass nestedClass, TypeMappingInfo typeMappingInfo) { |
| String packageName; |
| String qualifiedClassName; |
| QName qName = null; |
| if (helper.getJavaClass(ManyValue.class).isAssignableFrom(componentClass)) { |
| packageName = componentClass.getPackageName(); |
| qualifiedClassName = nestedClass.getQualifiedName() + ARRAY_CLASS_NAME_SUFFIX; |
| } else { |
| if (componentClass.isPrimitive()) { |
| packageName = ARRAY_PACKAGE_NAME; |
| qualifiedClassName = packageName + DOT_CHR + componentClass.getName() + ARRAY_CLASS_NAME_SUFFIX; |
| } else { |
| packageName = ARRAY_PACKAGE_NAME + DOT_CHR + componentClass.getPackageName(); |
| if (componentClass.isMemberClass()) { |
| qualifiedClassName = componentClass.getName(); |
| qualifiedClassName = qualifiedClassName.substring(qualifiedClassName.indexOf(DOLLAR_SIGN_CHR) + 1); |
| qualifiedClassName = ARRAY_PACKAGE_NAME + DOT_CHR + componentClass.getPackageName() + DOT_CHR + qualifiedClassName + ARRAY_CLASS_NAME_SUFFIX; |
| } else { |
| qualifiedClassName = ARRAY_PACKAGE_NAME + DOT_CHR + componentClass.getQualifiedName() + ARRAY_CLASS_NAME_SUFFIX; |
| } |
| } |
| |
| if (componentClass.isPrimitive() || helper.isBuiltInJavaType(componentClass)) { |
| qName = (QName) helper.getXMLToJavaTypeMap().get(componentClass.getQualifiedName()); |
| if(null != qName) { |
| packageName = ARRAY_PACKAGE_NAME; |
| qualifiedClassName = ARRAY_PACKAGE_NAME + DOT_CHR + qName.getLocalPart() + ARRAY_CLASS_NAME_SUFFIX; |
| } |
| PackageInfo namespaceInfo = getPackageToPackageInfoMappings().get(packageName); |
| if (namespaceInfo == null) { |
| namespaceInfo = new PackageInfo(); |
| namespaceInfo.setNamespaceInfo(new NamespaceInfo()); |
| namespaceInfo.setNamespace(ARRAY_NAMESPACE); |
| namespaceInfo.setNamespaceResolver(new NamespaceResolver()); |
| getPackageToPackageInfoMappings().put(packageName, namespaceInfo); |
| } |
| } else { |
| PackageInfo namespaceInfo = getPackageInfoForPackage(componentClass.getPackage(), componentClass.getPackageName()); |
| getPackageToPackageInfoMappings().put(packageName, namespaceInfo); |
| } |
| } |
| |
| try { |
| String qualifiedInternalClassName = qualifiedClassName.replace(DOT_CHR, SLASH_CHR); |
| if (helper.getJavaClass(ManyValue.class).isAssignableFrom(componentClass)) { |
| return generateClassFromBytes(qualifiedClassName, generateMultiDimensionalManyValueClass(typeMappingInfo, null, MultiDimensionalArrayValue.class, qualifiedInternalClassName, componentClass, arrayClass.getComponentType())); |
| } else { |
| return generateClassFromBytes(qualifiedClassName, generateManyValue(typeMappingInfo, null, ArrayValue.class, qualifiedInternalClassName, componentClass, componentClass)); |
| } |
| } catch(LinkageError e) { |
| if(null != qName) { |
| throw JAXBException.nameCollision(qName.getNamespaceURI(), qName.getLocalPart()); |
| } |
| throw e; |
| } |
| } |
| |
| private JavaClass getObjectType(JavaClass javaClass) { |
| if (javaClass.isPrimitive()) { |
| String primitiveClassName = javaClass.getRawName(); |
| Class primitiveClass = getPrimitiveClass(primitiveClassName); |
| return helper.getJavaClass(getObjectClass(primitiveClass)); |
| } |
| return javaClass; |
| } |
| |
| private Class generateCollectionValue(JavaClass collectionClass, TypeMappingInfo typeMappingInfo, Class xmlElementType, List<JavaClass> classesToProcess) { |
| |
| JavaClass componentClass; |
| |
| if (typeMappingInfo != null && xmlElementType != null) { |
| componentClass = helper.getJavaClass(xmlElementType); |
| } else{ |
| Collection args = collectionClass.getActualTypeArguments(); |
| if(args.size() >0 ){ |
| componentClass = ((JavaClass) args.toArray()[0]); |
| }else{ |
| componentClass = helper.getJavaClass(Object.class); |
| } |
| } |
| |
| boolean multiDimensional = false; |
| if (componentClass.isPrimitive()) { |
| Class primitiveClass = getPrimitiveClass(componentClass.getRawName()); |
| componentClass = helper.getJavaClass(getObjectClass(primitiveClass)); |
| } else if(helper.getJavaClass(Collection.class).isAssignableFrom(componentClass)) { |
| multiDimensional = true; |
| java.lang.reflect.Type nestedCollectionType = getNestedCollectionType(typeMappingInfo); |
| Class nestedCollectionClass = collectionClassesToGeneratedClasses.get(nestedCollectionType); |
| if (nestedCollectionClass == null) { |
| nestedCollectionClass = generateCollectionValue(componentClass, typeMappingInfo, xmlElementType, classesToProcess); |
| collectionClassesToGeneratedClasses.put(nestedCollectionType, nestedCollectionClass); |
| classesToProcess.add(helper.getJavaClass(nestedCollectionClass)); |
| } |
| componentClass = helper.getJavaClass(nestedCollectionClass); |
| } else if(componentClass.isArray()) { |
| if(componentClass.getName().equals("[B")) { |
| multiDimensional = false; |
| } else { |
| multiDimensional = true; |
| Class nestedArrayClass = arrayClassesToGeneratedClasses.get(componentClass.getName()); |
| if (nestedArrayClass == null) { |
| nestedArrayClass = generateWrapperForArrayClass(componentClass, typeMappingInfo, xmlElementType, classesToProcess); |
| arrayClassesToGeneratedClasses.put(componentClass.getName(), nestedArrayClass); |
| } |
| componentClass = helper.getJavaClass(nestedArrayClass); |
| } |
| } |
| |
| PackageInfo packageInfo = packageToPackageInfoMappings.get(collectionClass.getPackageName()); |
| |
| String namespace = EMPTY_STRING; |
| if (this.defaultTargetNamespace != null) { |
| namespace = this.defaultTargetNamespace; |
| } |
| |
| PackageInfo componentNamespaceInfo = getPackageInfoForPackage(componentClass); |
| String packageName = componentClass.getPackageName(); |
| packageName = "jaxb.dev.java.net." + packageName; |
| if (packageInfo == null) { |
| packageInfo = getPackageToPackageInfoMappings().get(packageName); |
| } else { |
| getPackageToPackageInfoMappings().put(packageName, packageInfo); |
| if (packageInfo.getNamespace() != null) { |
| namespace = packageInfo.getNamespace(); |
| } |
| } |
| if (packageInfo == null) { |
| if (componentNamespaceInfo != null) { |
| packageInfo = componentNamespaceInfo; |
| } else { |
| packageInfo = new PackageInfo(); |
| packageInfo.setNamespaceInfo(new NamespaceInfo()); |
| packageInfo.setNamespaceResolver(new NamespaceResolver()); |
| } |
| getPackageToPackageInfoMappings().put(packageName, packageInfo); |
| } |
| |
| String name = componentClass.getName(); |
| if("[B".equals(name)) { |
| name = "byteArray"; |
| } |
| |
| int beginIndex = name.lastIndexOf(DOT_CHR) + 1; |
| name = name.substring(beginIndex); |
| int dollarIndex = name.indexOf(DOLLAR_SIGN_CHR); |
| if (dollarIndex > -1) { |
| name = name.substring(dollarIndex + 1); |
| } |
| String collectionClassRawName = collectionClass.getRawName(); |
| |
| String collectionClassShortName = collectionClassRawName.substring(collectionClassRawName.lastIndexOf(DOT_CHR) + 1); |
| String suggestedClassName = collectionClassShortName + "Of" + name; |
| String qualifiedClassName = packageName + DOT_CHR + suggestedClassName; |
| qualifiedClassName = getNextAvailableClassName(qualifiedClassName); |
| |
| String qualifiedInternalClassName = qualifiedClassName.replace(DOT_CHR, SLASH_CHR); |
| |
| byte[] classBytes; |
| if(multiDimensional) { |
| classBytes = generateMultiDimensionalManyValueClass(typeMappingInfo, namespace, MultiDimensionalCollectionValue.class, qualifiedInternalClassName, componentClass, collectionClass); |
| } else { |
| classBytes = generateManyValue(typeMappingInfo, namespace, CollectionValue.class, qualifiedInternalClassName, componentClass, collectionClass); |
| } |
| return generateClassFromBytes(qualifiedClassName, classBytes); |
| } |
| |
| private java.lang.reflect.Type getNestedCollectionType(TypeMappingInfo mappingInfo) { |
| java.lang.reflect.Type result = null; |
| if (mappingInfo != null && mappingInfo.getType() != null) { |
| // called for a collection, type must be parametrized ... |
| ParameterizedType pType = (ParameterizedType) mappingInfo.getType(); |
| java.lang.reflect.Type[] actualTypeArguments = pType.getActualTypeArguments(); |
| result = actualTypeArguments != null && actualTypeArguments.length > 0 ? actualTypeArguments[0] : null; |
| } |
| if (result == null) { |
| getLogger().logWarning("cant_get_nested_collection_type", new Object[]{}); |
| } |
| return result; |
| } |
| |
| private byte[] generateManyValue(TypeMappingInfo typeMappingInfo, String namespace, Class superType, String classNameSeparatedBySlash, JavaClass componentType, JavaClass containerType) { |
| EclipseLinkASMClassWriter cw = new EclipseLinkASMClassWriter(); |
| generateManyValueClass(cw, typeMappingInfo, namespace, superType, classNameSeparatedBySlash, componentType, containerType); |
| cw.visitEnd(); |
| return cw.toByteArray(); |
| } |
| |
| private void generateManyValueClass(EclipseLinkASMClassWriter cw, TypeMappingInfo typeMappingInfo, String namespace, Class superType, String classNameSeparatedBySlash, JavaClass componentType, JavaClass containerType) { |
| String componentClassNameSeparatedBySlash = getObjectType(componentType).getQualifiedName().replace(DOT_CHR, SLASH_CHR); |
| String containerClassNameSeperatedBySlash = containerType.getQualifiedName().replace(DOT_CHR, SLASH_CHR); |
| if("[B".equals(componentClassNameSeparatedBySlash)) { |
| cw.visit(Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, classNameSeparatedBySlash, "L" + Type.getInternalName(superType) + "<" + componentClassNameSeparatedBySlash + ">;", Type.getInternalName(superType), null); |
| } else { |
| cw.visit(Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, classNameSeparatedBySlash, "L" + Type.getInternalName(superType) + "<L" + componentClassNameSeparatedBySlash + ";>;", Type.getInternalName(superType), null); |
| } |
| |
| // Write @XmlType(namespace) |
| AnnotationVisitor av = cw.visitAnnotation("Ljakarta/xml/bind/annotation/XmlType;", true); |
| if(null != namespace) { |
| av.visit("namespace", namespace); |
| } |
| if(classNameSeparatedBySlash.startsWith(ARRAY_PACKAGE_NAME.replace('.', '/')) && classNameSeparatedBySlash.contains("QName") ) { |
| av.visit("name", classNameSeparatedBySlash.substring(classNameSeparatedBySlash.lastIndexOf('/') + 1)); |
| } |
| av.visitEnd(); |
| |
| // Public No-Arg Constructor |
| MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); |
| mv.visitCode(); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(superType), "<init>", "()V", false); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| |
| if(!componentType.isPrimitive() && ArrayValue.class.isAssignableFrom(superType)){ |
| |
| //@Override |
| //public Object getItem() { |
| // if(null == adaptedValue) { |
| // return null; |
| // } |
| // int len = adaptedValue.size(); |
| // Float[] array = new Float[len]; |
| // adaptedValue.toArray(array); |
| // return array; |
| // } |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getItem", "()Ljava/lang/Object;", null, null); |
| mv.visitCode(); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitFieldInsn(Opcodes.GETFIELD, classNameSeparatedBySlash, "adaptedValue", "Ljava/util/Collection;"); |
| Label l0 = new Label(); |
| mv.visitJumpInsn(Opcodes.IFNONNULL, l0); |
| mv.visitInsn(Opcodes.ACONST_NULL); |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitLabel(l0); |
| mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitFieldInsn(Opcodes.GETFIELD, classNameSeparatedBySlash, "adaptedValue", "Ljava/util/Collection;"); |
| mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Collection", "size", "()I", true); |
| mv.visitVarInsn(Opcodes.ISTORE, 1); |
| mv.visitVarInsn(Opcodes.ILOAD, 1); |
| mv.visitTypeInsn(Opcodes.ANEWARRAY, componentClassNameSeparatedBySlash); |
| mv.visitVarInsn(Opcodes.ASTORE, 2); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitFieldInsn(Opcodes.GETFIELD, classNameSeparatedBySlash, "adaptedValue", "Ljava/util/Collection;"); |
| mv.visitVarInsn(Opcodes.ALOAD, 2); |
| mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Collection", "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;", true); |
| mv.visitInsn(Opcodes.POP); |
| |
| mv.visitVarInsn(Opcodes.ALOAD, 2); |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitMaxs(2, 3); |
| mv.visitEnd(); |
| |
| |
| //@Override |
| //public void setItem(Object array) { |
| // Float[] floatArray = (Float[])array; |
| // adaptedValue = (Collection<T>) Arrays.asList(floatArray); |
| //} |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setItem", "(Ljava/lang/Object;)V", null, null); |
| mv.visitCode(); |
| mv.visitVarInsn(Opcodes.ALOAD, 1); |
| mv.visitTypeInsn(Opcodes.CHECKCAST, "[L"+componentClassNameSeparatedBySlash+";"); |
| mv.visitVarInsn(Opcodes.ASTORE, 2); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitVarInsn(Opcodes.ALOAD, 2); |
| mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/util/Arrays", "asList", "([Ljava/lang/Object;)Ljava/util/List;", false); |
| mv.visitFieldInsn(Opcodes.PUTFIELD, classNameSeparatedBySlash, "adaptedValue", "Ljava/util/Collection;"); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(2, 3); |
| mv.visitEnd(); |
| } |
| |
| |
| // @XmlElement(name="item", nillable=true) |
| // public Collection<COMPONENT_TYPE> getAdaptedValue() { |
| // return super.getAdaptedValue(); |
| // } |
| // OR |
| // @XmlValue |
| // public Collection<COMPONENT_TYPE> getAdaptedValue() { |
| // return super.getAdaptedValue(); |
| // } |
| if("[B".equals(componentClassNameSeparatedBySlash)) { |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getAdaptedValue", "()Ljava/util/Collection;", "()Ljava/util/Collection<" + componentClassNameSeparatedBySlash + ">;", null); |
| } else { |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "getAdaptedValue", "()Ljava/util/Collection;", "()Ljava/util/Collection<L" + componentClassNameSeparatedBySlash + ";>;", null); |
| } |
| // Copy annotations |
| boolean hasXmlList = false; |
| Annotation[] annotations; |
| if (typeMappingInfo != null && ((annotations = getAnnotations(typeMappingInfo)) != null)) { |
| for (Annotation annotation : annotations) { |
| if(!(annotation instanceof XmlElement || annotation instanceof XmlJavaTypeAdapter)) { |
| Class<? extends Annotation> annotationType = annotation.annotationType(); |
| //if(annotationType.equals(XmlList.class)) { |
| if(annotation instanceof XmlList) { |
| hasXmlList = true; |
| } |
| av = mv.visitAnnotation(L + annotationType.getName().replace(DOT_CHR, SLASH_CHR) + SEMI_COLON, true); |
| for (Method next : annotation.annotationType().getDeclaredMethods()) { |
| try { |
| Object nextValue = next.invoke(annotation, new Object[] {}); |
| if (nextValue instanceof Class) { |
| nextValue = Type.getType(L + ((Class) nextValue).getName().replace(DOT_CHR, SLASH_CHR) + SEMI_COLON); |
| } |
| av.visit(next.getName(), nextValue); |
| } catch (InvocationTargetException ex) { |
| } catch (IllegalAccessException ex) { |
| } |
| } |
| av.visitEnd(); |
| } |
| } |
| } |
| if(hasXmlList) { |
| // @XmlValue |
| av = mv.visitAnnotation("Ljakarta/xml/bind/annotation/XmlValue;", true); |
| av = mv.visitAnnotation("Lorg/eclipse/persistence/oxm/annotations/XmlValueExtension;", true); |
| av.visitEnd(); |
| } else { |
| // @XmlElement(name="item", nillable=true) |
| av = mv.visitAnnotation("Ljakarta/xml/bind/annotation/XmlElement;", true); |
| av.visit("name", ITEM); |
| av.visit("nillable", true); |
| av.visitEnd(); |
| } |
| |
| mv.visitCode(); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(superType), "getAdaptedValue", "()Ljava/util/Collection;", false); |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| |
| // public void setAdaptedValue(Collection<COMPONENT_TYPE> adaptedValue) { |
| // super.setAdaptedValue(adaptedValue); |
| // } |
| mv = cw.visitMethod(Opcodes.ACC_PUBLIC, "setAdaptedValue", "(Ljava/util/Collection;)V", "(Ljava/util/Collection<L" + componentClassNameSeparatedBySlash + ";>;)V", null); |
| mv.visitCode(); |
| mv.visitVarInsn(Opcodes.ALOAD, 0); |
| mv.visitVarInsn(Opcodes.ALOAD, 1); |
| mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(superType), "setAdaptedValue", "(Ljava/util/Collection;)V", false); |
| mv.visitInsn(Opcodes.RETURN); |
| mv.visitMaxs(2, 2); |
| mv.visitEnd(); |
| |
| // public Class<?> containerClass() { |
| // return CONTAINER_TYPE.class; |
| // } |
| mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "containerClass", "()Ljava/lang/Class;", "()Ljava/lang/Class<*>;", null); |
| mv.visitCode(); |
| if(componentType.isPrimitive()) { |
| mv.visitFieldInsn(Opcodes.GETSTATIC, getObjectType(componentType).getQualifiedName().replace(DOT_CHR, SLASH_CHR), "TYPE", "Ljava/lang/Class;"); |
| } else { |
| if(containerClassNameSeperatedBySlash.contains(";")) { |
| mv.visitLdcInsn(Type.getType(containerClassNameSeperatedBySlash)); |
| } else { |
| mv.visitLdcInsn(Type.getType("L" + containerClassNameSeperatedBySlash + ";")); |
| } |
| } |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| } |
| |
| private byte[] generateMultiDimensionalManyValueClass(TypeMappingInfo typeMappingInfo, String namespace, Class superType, String classNameSeparatedBySlash, JavaClass componentType, JavaClass containerType) { |
| EclipseLinkASMClassWriter cw = new EclipseLinkASMClassWriter(); |
| generateManyValueClass(cw, typeMappingInfo, namespace, superType, classNameSeparatedBySlash, componentType, containerType); |
| generateMultiDimensionalManyValueClass(cw, componentType); |
| cw.visitEnd(); |
| return cw.toByteArray(); |
| } |
| |
| private void generateMultiDimensionalManyValueClass(ClassWriter cw, JavaClass componentType) { |
| // public Class<?> componentClass() { |
| // return COMPONENT_TYPE.class; |
| // } |
| String componentClassNameSeparatedBySlash = componentType.getQualifiedName().replace(DOT_CHR, SLASH_CHR); |
| MethodVisitor mv = cw.visitMethod(Opcodes.ACC_PROTECTED, "componentClass", "()Ljava/lang/Class;", "()Ljava/lang/Class<L" + componentClassNameSeparatedBySlash + ";>;", null); |
| mv.visitCode(); |
| mv.visitLdcInsn(Type.getType("L" + componentClassNameSeparatedBySlash + ";")); |
| mv.visitInsn(Opcodes.ARETURN); |
| mv.visitMaxs(1, 1); |
| mv.visitEnd(); |
| } |
| |
| private Class generateClassFromBytes(String className, byte[] classBytes) { |
| JaxbClassLoader loader = (JaxbClassLoader) helper.getClassLoader(); |
| Class generatedClass = loader.generateClass(className, classBytes); |
| return generatedClass; |
| } |
| |
| /** |
| * Inner class used for ordering a list of Properties alphabetically by |
| * property name. |
| * |
| */ |
| private static final class PropertyComparitor implements Comparator<Property> { |
| @Override |
| public int compare(Property p1, Property p2) { |
| return p1.getPropertyName().compareTo(p2.getPropertyName()); |
| } |
| } |
| |
| private String getNextAvailableClassName(String suggestedName) { |
| int counter = 1; |
| return getNextAvailableClassName(suggestedName, suggestedName, counter); |
| } |
| |
| private String getNextAvailableClassName(String suggestedBaseName, String suggestedName, int counter) { |
| |
| Iterator<Class> iter = typeMappingInfosToGeneratedClasses.values().iterator(); |
| while (iter.hasNext()) { |
| Class nextClass = iter.next(); |
| if (nextClass.getName().equals(suggestedName)) { |
| counter = counter + 1; |
| return getNextAvailableClassName(suggestedBaseName, suggestedBaseName + counter, counter); |
| } |
| } |
| return suggestedName; |
| } |
| |
| private Class getPrimitiveClass(String primitiveClassName) { |
| return ConversionManager.getDefaultManager().convertClassNameToClass(primitiveClassName); |
| } |
| |
| private Class getObjectClass(Class primitiveClass) { |
| return ConversionManager.getObjectClass(primitiveClass); |
| } |
| |
| public Map<java.lang.reflect.Type, Class> getCollectionClassesToGeneratedClasses() { |
| return collectionClassesToGeneratedClasses; |
| } |
| |
| public Map<String, Class> getArrayClassesToGeneratedClasses() { |
| return arrayClassesToGeneratedClasses; |
| } |
| |
| public Map<Class, java.lang.reflect.Type> getGeneratedClassesToCollectionClasses() { |
| return generatedClassesToCollectionClasses; |
| } |
| |
| public Map<Class, JavaClass> getGeneratedClassesToArrayClasses() { |
| return generatedClassesToArrayClasses; |
| } |
| |
| /** |
| * Convenience method for returning all of the TypeInfo objects for a given |
| * package name. |
| * |
| * This method is inefficient as we need to iterate over the entire typeinfo |
| * map for each call. We should eventually store the TypeInfos in a Map |
| * based on package name, i.e.: |
| * |
| * Map {@literal <String, Map<String, TypeInfo>>} |
| * |
| * @return List of TypeInfo objects for a given package name |
| */ |
| public Map<String, TypeInfo> getTypeInfosForPackage(String packageName) { |
| Map<String, TypeInfo> typeInfos = new HashMap<String, TypeInfo>(); |
| List<JavaClass> jClasses = getTypeInfoClasses(); |
| for (JavaClass jClass : jClasses) { |
| if (jClass.getPackageName().equals(packageName)) { |
| String key = jClass.getQualifiedName(); |
| typeInfos.put(key, this.typeInfos.get(key)); |
| } |
| } |
| return typeInfos; |
| } |
| |
| /** |
| * Set namespace override info from XML bindings file. This will typically |
| * be called from the XMLProcessor. |
| * |
| */ |
| public void setPackageToNamespaceMappings(HashMap<String, NamespaceInfo> packageToNamespaceMappings) { |
| //this.packageToNamespaceMappings = packageToNamespaceMappings; |
| } |
| |
| public void setPackageToPackageInfoMappings(HashMap<String, PackageInfo> packageToPackageInfoMappings) { |
| this.packageToPackageInfoMappings = packageToPackageInfoMappings; |
| } |
| |
| public SchemaTypeInfo addClass(JavaClass javaClass) { |
| if (javaClass == null) { |
| return null; |
| } else if (helper.isAnnotationPresent(javaClass, XmlTransient.class)) { |
| return null; |
| } |
| |
| if (typeInfos == null) { |
| // this is the first class. Initialize all the properties |
| this.typeInfoClasses = new ArrayList<JavaClass>(); |
| this.typeInfos = new HashMap<String, TypeInfo>(); |
| this.typeQNames = new ArrayList<QName>(); |
| this.userDefinedSchemaTypes = new HashMap<String, QName>(); |
| this.packageToPackageInfoMappings = new HashMap<String, PackageInfo>(); |
| } |
| |
| JavaClass[] jClasses = new JavaClass[] { javaClass }; |
| buildNewTypeInfo(jClasses); |
| TypeInfo info = typeInfos.get(javaClass.getQualifiedName()); |
| |
| PackageInfo packageInfo; |
| String packageName = javaClass.getPackageName(); |
| packageInfo = this.packageToPackageInfoMappings.get(packageName); |
| |
| SchemaTypeInfo schemaInfo = new SchemaTypeInfo(); |
| schemaInfo.setSchemaTypeName(new QName(info.getClassNamespace(), info.getSchemaTypeName())); |
| |
| if (info.isSetXmlRootElement()) { |
| org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement xmlRE = info.getXmlRootElement(); |
| String elementName = xmlRE.getName(); |
| if (elementName.equals(XMLProcessor.DEFAULT) || elementName.equals(EMPTY_STRING)) { |
| try { |
| elementName = info.getXmlNameTransformer().transformRootElementName(javaClass.getName()); |
| } catch (Exception ex) { |
| throw org.eclipse.persistence.exceptions.JAXBException.exceptionDuringNameTransformation(javaClass.getName(), info.getXmlNameTransformer().getClass().getName(), ex); |
| } |
| } |
| String rootNamespace = xmlRE.getNamespace(); |
| QName rootElemName = null; |
| if (rootNamespace.equals(XMLProcessor.DEFAULT)) { |
| rootElemName = new QName(packageInfo.getNamespace(), elementName); |
| } else { |
| rootElemName = new QName(rootNamespace, elementName); |
| } |
| schemaInfo.getGlobalElementDeclarations().add(rootElemName); |
| ElementDeclaration declaration = new ElementDeclaration(rootElemName, javaClass, javaClass.getRawName(), false); |
| addGlobalElement(rootElemName, declaration); |
| } |
| |
| return schemaInfo; |
| } |
| |
| /** |
| * Convenience method which class pre and postBuildTypeInfo for a given set |
| * of JavaClasses. |
| * |
| */ |
| public void buildNewTypeInfo(JavaClass[] javaClasses) { |
| preBuildTypeInfo(javaClasses); |
| javaClasses = postBuildTypeInfo(javaClasses); |
| for(JavaClass next:javaClasses) { |
| processPropertyTypes(next); |
| } |
| } |
| |
| /** |
| * Pre-process a descriptor customizer. Here, the given JavaClass is checked |
| * for the existence of an @XmlCustomizer annotation. |
| * |
| * Note that the post processing of the descriptor customizers will take |
| * place in MappingsGenerator's generateProject method, after the |
| * descriptors and mappings have been generated. |
| * |
| * @see XmlCustomizer |
| * @see MappingsGenerator |
| */ |
| private void preProcessCustomizer(JavaClass jClass, TypeInfo tInfo) { |
| XmlCustomizer xmlCustomizer = (XmlCustomizer) helper.getAnnotation(jClass, XmlCustomizer.class); |
| if (xmlCustomizer != null) { |
| tInfo.setXmlCustomizer(xmlCustomizer.value().getName()); |
| } |
| } |
| |
| /** |
| * Lazy load the metadata logger. |
| * |
| */ |
| private JAXBMetadataLogger getLogger() { |
| if (logger == null) { |
| logger = new JAXBMetadataLogger(); |
| } |
| return logger; |
| } |
| |
| /** |
| * Return the Helper object set on this processor. |
| * |
| */ |
| Helper getHelper() { |
| return this.helper; |
| } |
| |
| public boolean isDefaultNamespaceAllowed() { |
| return isDefaultNamespaceAllowed; |
| } |
| |
| public List<ElementDeclaration> getLocalElements() { |
| return this.localElements; |
| } |
| |
| public Map<TypeMappingInfo, Class> getTypeMappingInfosToGeneratedClasses() { |
| return this.typeMappingInfosToGeneratedClasses; |
| } |
| |
| public Map<TypeMappingInfo, Class> getTypeMappingInfoToAdapterClasses() { |
| return this.typeMappingInfoToAdapterClasses; |
| } |
| |
| /** |
| * Add an XmlRegistry to ObjectFactory class name pair to the map. |
| * |
| * @param factoryClassName |
| * ObjectFactory class name |
| * @param xmlReg |
| * org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry instance |
| */ |
| public void addXmlRegistry(String factoryClassName, org.eclipse.persistence.jaxb.xmlmodel.XmlRegistry xmlReg) { |
| this.xmlRegistries.put(factoryClassName, xmlReg); |
| } |
| |
| /** |
| * Convenience method for determining if a given JavaClass should be |
| * processed as an ObjectFactory class. |
| * |
| * @return true if the JavaClass is annotated with @XmlRegistry or the map |
| * of XmlRegistries contains a key equal to the JavaClass' qualified |
| * name |
| */ |
| private boolean isXmlRegistry(JavaClass javaClass) { |
| if (javaClass == null) { |
| return false; |
| } |
| return (helper.isAnnotationPresent(javaClass, XmlRegistry.class) || xmlRegistries.get(javaClass.getQualifiedName()) != null); |
| } |
| |
| public Map<TypeMappingInfo, QName> getTypeMappingInfosToSchemaTypes() { |
| return this.typeMappingInfosToSchemaTypes; |
| } |
| |
| String getDefaultTargetNamespace() { |
| return this.defaultTargetNamespace; |
| } |
| |
| void setDefaultTargetNamespace(String defaultTargetNamespace) { |
| this.defaultTargetNamespace = defaultTargetNamespace; |
| } |
| |
| public void setDefaultNamespaceAllowed(boolean isDefaultNamespaceAllowed) { |
| this.isDefaultNamespaceAllowed = isDefaultNamespaceAllowed; |
| } |
| |
| Map<QName, ElementDeclaration> getElementDeclarationsForScope(String scopeClassName) { |
| return this.elementDeclarations.get(scopeClassName); |
| } |
| |
| private void addGlobalElement(QName key, ElementDeclaration declaration){ |
| getGlobalElements().put(key, declaration); |
| classesToProcessPropertyTypes.add(declaration.getJavaType()); |
| } |
| |
| private Map<Object, Object> createUserPropertiesMap(XmlProperty[] properties) { |
| Map<Object, Object> propMap = new HashMap<Object, Object>(); |
| for (XmlProperty prop : properties) { |
| Object pvalue = prop.value(); |
| if (!(prop.valueType() == String.class)) { |
| pvalue = XMLConversionManager.getDefaultXMLManager().convertObject(prop.value(), prop.valueType()); |
| } |
| propMap.put(prop.name(), pvalue); |
| } |
| return propMap; |
| } |
| |
| /** |
| * Indicates if a given Property represents an MTOM attachment. Will return |
| * true if the given Property's actual type is one of: |
| * |
| * - DataHandler - byte[] - Byte[] - Image - Source - MimeMultipart |
| * |
| */ |
| public boolean isMtomAttachment(Property property) { |
| JavaClass ptype = property.getActualType(); |
| return (areEquals(ptype, JAVAX_ACTIVATION_DATAHANDLER) || areEquals(ptype, byte[].class) || areEquals(ptype, Image.class) || areEquals(ptype, Source.class) || areEquals(ptype, JAVAX_MAIL_INTERNET_MIMEMULTIPART)); |
| } |
| |
| public boolean hasSwaRef() { |
| return this.hasSwaRef; |
| } |
| |
| public void setHasSwaRef(boolean swaRef) { |
| this.hasSwaRef = swaRef; |
| } |
| |
| public List getReferencedByTransformer(){ |
| return referencedByTransformer; |
| } |
| |
| /** |
| * Indicates whether this AnnotationsProcessor has been configured to enable |
| * processing of XmlAccessorFactory annotations. |
| * |
| * @see "com.sun.xml.bind.XmlAccessorFactory" |
| */ |
| public boolean isXmlAccessorFactorySupport() { |
| return xmlAccessorFactorySupport; |
| } |
| |
| /** |
| * Sets whether this AnnotationsProcessor should process XmlAccessorFactory annotations. |
| * |
| * @see "com.sun.xml.bind.XmlAccessorFactory" |
| */ |
| public void setXmlAccessorFactorySupport(boolean value) { |
| this.xmlAccessorFactorySupport = value; |
| } |
| |
| public void setHasXmlBindings(boolean b) { |
| this.hasXmlBindings = true; |
| } |
| |
| public boolean hasXmlBindings() { |
| return this.hasXmlBindings; |
| } |
| } |