org.eclipse.persistence.jaxb.compiler.CompilerHelper Maven / Gradle / Ivy
/*
* 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:
// Denise Smith - January, 2010 - 2.0.1
package org.eclipse.persistence.jaxb.compiler;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Unmarshaller;
import jakarta.xml.bind.annotation.XmlElement;
import jakarta.xml.bind.annotation.XmlList;
import jakarta.xml.bind.annotation.adapters.XmlAdapter;
import jakarta.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import org.eclipse.persistence.internal.jaxb.AccessorFactoryWrapper;
import org.eclipse.persistence.internal.jaxb.JaxbClassLoader;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.JAXBContext;
import org.eclipse.persistence.jaxb.TypeMappingInfo;
import org.eclipse.persistence.jaxb.javamodel.Helper;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.javamodel.JavaField;
import org.eclipse.persistence.jaxb.javamodel.JavaMethod;
import org.eclipse.persistence.jaxb.javamodel.reflection.JavaClassImpl;
import org.eclipse.persistence.jaxb.xmlmodel.XmlJoinNodes;
/**
* Helper class for code that needs to be shared between AnnotationsProcessor,
* MappingsGenerator, SchemaGenerator
*/
public class CompilerHelper {
public static final String XML_LOCATION_ANNOTATION_NAME = "org.glassfish.jaxb.core.annotation.XmlLocation";
public static final String OLD_XML_LOCATION_ANNOTATION_NAME = "com.sun.xml.bind.annotation.XmlLocation";
public static final String INTERNAL_XML_LOCATION_ANNOTATION_NAME = "com.sun.xml.internal.bind.annotation.XmlLocation";
private static final String XML_ACCESSOR_FACTORY_ANNOTATION_NAME = "org.glassfish.jaxb.runtime.XmlAccessorFactory";
private static final String OLD_ACCESSOR_FACTORY_ANNOTATION_NAME = "com.sun.xml.bind.XmlAccessorFactory";
private static final String INTERNAL_ACCESSOR_FACTORY_ANNOTATION_NAME = "com.sun.xml.internal.bind.XmlAccessorFactory";
private static final String METADATA_MODEL_PACKAGE = "org.eclipse.persistence.jaxb.xmlmodel";
public static Class> ACCESSOR_FACTORY_ANNOTATION_CLASS = null;
public static Method ACCESSOR_FACTORY_VALUE_METHOD = null;
public static Class> OLD_ACCESSOR_FACTORY_ANNOTATION_CLASS = null;
public static Method OLD_ACCESSOR_FACTORY_VALUE_METHOD = null;
public static Class> INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS = null;
public static Method INTERNAL_ACCESSOR_FACTORY_VALUE_METHOD = null;
public static Class> XML_LOCATION_ANNOTATION_CLASS = null;
public static Class> OLD_XML_LOCATION_ANNOTATION_CLASS = null;
public static Class> INTERNAL_XML_LOCATION_ANNOTATION_CLASS = null;
private static JAXBContext xmlBindingsModelContext;
static {
try {
ACCESSOR_FACTORY_ANNOTATION_CLASS = PrivilegedAccessHelper.getClassForName(XML_ACCESSOR_FACTORY_ANNOTATION_NAME, true, CompilerHelper.class.getClassLoader());
ACCESSOR_FACTORY_VALUE_METHOD = PrivilegedAccessHelper.getDeclaredMethod(ACCESSOR_FACTORY_ANNOTATION_CLASS, "value", new Class>[]{});
} catch (Exception ex) {
}
try {
XML_LOCATION_ANNOTATION_CLASS = PrivilegedAccessHelper.getClassForName(XML_LOCATION_ANNOTATION_NAME, true, CompilerHelper.class.getClassLoader());
} catch (Exception ex) {
}
try {
OLD_XML_LOCATION_ANNOTATION_CLASS = PrivilegedAccessHelper.getClassForName(OLD_XML_LOCATION_ANNOTATION_NAME, true, CompilerHelper.class.getClassLoader());
} catch (Exception ex) {
}
try{
OLD_ACCESSOR_FACTORY_ANNOTATION_CLASS = PrivilegedAccessHelper.getClassForName(OLD_ACCESSOR_FACTORY_ANNOTATION_NAME);
OLD_ACCESSOR_FACTORY_VALUE_METHOD = PrivilegedAccessHelper.getDeclaredMethod(OLD_ACCESSOR_FACTORY_ANNOTATION_CLASS, "value", new Class>[]{});
} catch (Exception ex) {
}
try{
INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS = PrivilegedAccessHelper.getClassForName(INTERNAL_ACCESSOR_FACTORY_ANNOTATION_NAME);
INTERNAL_ACCESSOR_FACTORY_VALUE_METHOD = PrivilegedAccessHelper.getDeclaredMethod(INTERNAL_ACCESSOR_FACTORY_ANNOTATION_CLASS, "value", new Class>[]{});
} catch (Exception ex) {
}
try{
INTERNAL_XML_LOCATION_ANNOTATION_CLASS = PrivilegedAccessHelper.getClassForName(INTERNAL_XML_LOCATION_ANNOTATION_NAME);
}catch (Exception ex) {
}
}
/**
* If 2 TypeMappingInfo objects would generate the same generated class (and
* therefore complex type) then return the existing class otherwise return
* null.
*/
static Class> getExisitingGeneratedClass(TypeMappingInfo tmi, Map> typeMappingInfoToGeneratedClasses, Map> typeMappingInfoToAdapterClasses, ClassLoader loader) {
Iterator>> iter = typeMappingInfoToGeneratedClasses.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry> next = iter.next();
TypeMappingInfo nextTMI = next.getKey();
if (CompilerHelper.generatesSameComplexType(tmi, nextTMI, loader)) {
return next.getValue();
}
}
return null;
}
/**
* Return true if the two TypeMappingInfoObjects should generate the same
* complex type in the XSD
*/
private static boolean generatesSameComplexType(TypeMappingInfo tmi1, TypeMappingInfo tmi2, ClassLoader loader) {
org.eclipse.persistence.jaxb.xmlmodel.XmlElement element1 = null;
org.eclipse.persistence.jaxb.xmlmodel.XmlElement element2 = null;
if (tmi1.getXmlElement() != null) {
element1 = getXmlElement(tmi1.getXmlElement(), loader);
}
if (tmi2.getXmlElement() != null) {
element2 = getXmlElement(tmi2.getXmlElement(), loader);
}
Type actualType1 = getActualType(tmi1, element1);
Type actualType2 = getActualType(tmi2, element2);
if (!areTypesEqual(actualType1, actualType2)) {
return false;
}
if (!hasSameClassName(tmi1,tmi2)) {
return false;
}
boolean isXmlList1 = isXmlList(tmi1, element1);
boolean isXmlList2 = isXmlList(tmi2, element2);
if (isXmlList1) {
if (!isXmlList2) {
return false;
}
} else if (isXmlList2) {
return false;
}
return true;
}
/**
* Return true if tmi1 and tmi2 are instances of Class and have same class name.
*
* @param tmi1 instance of TypeMappingInfo
* @param tmi2 instance of typeMappingInfo
* @return true if TypeMappingInfos are instances of Class and have same class name
*/
private static boolean hasSameClassName(TypeMappingInfo tmi1, TypeMappingInfo tmi2) {
Type type1 = tmi1.getType();
Type type2 = tmi2.getType();
if (type1 != null && type2 == null) {
return false;
} else if (type1 == null && type2 != null) {
return false;
} else if (type1 instanceof Class> && type2 instanceof Class){
String typeName1 = ((Class)type1).getName();
String typeName2 = ((Class)type2).getName();
if (!typeName1.equals(typeName2)) {
return false;
}
}
return true;
}
/**
* Return if this TypeMappingInfo has an XmlList annotation or is specified
* to be an xmlList in an XMLElement override
*/
private static boolean isXmlList(TypeMappingInfo tmi, org.eclipse.persistence.jaxb.xmlmodel.XmlElement element) {
if (element != null && element.isXmlList()) {
return true;
}
if (tmi.getAnnotations() != null) {
for (int i = 0; i < tmi.getAnnotations().length; i++) {
java.lang.annotation.Annotation nextAnnotation = tmi.getAnnotations()[i];
if (nextAnnotation != null && nextAnnotation instanceof XmlList) {
return true;
}
}
}
return false;
}
/**
* Return true if the Types are equal. Accounts for Classes and
* Parameterized types or any combintation of the two.
*/
private static boolean areTypesEqual(java.lang.reflect.Type type, java.lang.reflect.Type type2) {
// handle null
if (type == null) {
return type2 == null;
} else if (type instanceof Class) {
if (type2 instanceof ParameterizedType) {
java.lang.reflect.Type rawType = ((ParameterizedType) type2).getRawType();
if (!areTypesEqual(type, rawType)) {
return false;
}
java.lang.reflect.Type[] args = ((ParameterizedType) type2).getActualTypeArguments();
for (int i = 0; i < args.length; i++) {
Type argType = getActualArgumentType(args[i]);
if (!areTypesEqual(Object.class, argType)) {
return false;
}
}
return true;
} else if (type2 instanceof Class) {
return type.equals(type2);
} else {
return false;
}
} else if (type instanceof ParameterizedType) {
if (type2 instanceof Class) {
java.lang.reflect.Type rawType = ((ParameterizedType) type).getRawType();
if (!areTypesEqual(type2, rawType)) {
return false;
}
java.lang.reflect.Type[] args = ((ParameterizedType) type).getActualTypeArguments();
for (int i = 0; i < args.length; i++) {
Type argType = getActualArgumentType(args[i]);
if (!areTypesEqual(Object.class, argType)) {
return false;
}
}
return true;
} else if (type2 instanceof ParameterizedType) {
// compare raw type
if (!areTypesEqual(((ParameterizedType) type).getRawType(),
((ParameterizedType) type2).getRawType())) {
return false;
}
java.lang.reflect.Type[] ta1 = ((ParameterizedType) type).getActualTypeArguments();
java.lang.reflect.Type[] ta2 = ((ParameterizedType) type2).getActualTypeArguments();
// check array length
if (ta1.length != ta2.length) {
return false;
}
for (int i = 0; i < ta1.length; i++) {
Type componentType1 = getActualArgumentType(ta1[i]);
Type componentType2 = getActualArgumentType(ta2[i]);
if (!areTypesEqual(componentType1, componentType2)) {
return false;
}
}
return true;
} else {
return false;
}
}
return false;
}
private static Type getActualArgumentType(Type argument){
if(argument instanceof WildcardType){
Type[] upperBounds = ((WildcardType)argument).getUpperBounds();
if(upperBounds != null && upperBounds.length >0){
return upperBounds[0];
}else{
return Object.class;
}
}else if (argument instanceof GenericArrayType){
return ((GenericArrayType)argument).getGenericComponentType();
}
return argument;
}
/**
* Convenience method for creating an XmlElement object based on a given
* Element. The method will load the eclipselink metadata model and
* unmarshal the Element. This assumes that the Element represents an
* xml-element to be unmarshalled.
*
*/
static org.eclipse.persistence.jaxb.xmlmodel.XmlElement getXmlElement(org.w3c.dom.Element xmlElementNode, ClassLoader classLoader) {
try {
Unmarshaller unmarshaller = CompilerHelper.getXmlBindingsModelContext().createUnmarshaller();
JAXBElement jelt = unmarshaller.unmarshal(xmlElementNode, org.eclipse.persistence.jaxb.xmlmodel.XmlElement.class);
return jelt.getValue();
} catch (jakarta.xml.bind.JAXBException jaxbEx) {
throw org.eclipse.persistence.exceptions.JAXBException.couldNotUnmarshalMetadata(jaxbEx);
}
}
/**
* If adapter class is null return null If there is a marshal method that
* returns something other than Object on the adapter class return the
* return type of that method Otherwise return Object.class
*/
static Class> getTypeFromAdapterClass(Class> adapterClass) {
if (adapterClass != null) {
Class
© 2015 - 2025 Weber Informatics LLC | Privacy Policy