All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.internal.jpa.weaving.TransformerFactory Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 1998, 2018 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
//     11/10/2011-2.4 Guy Pelletier
//       - 357474: Address primaryKey option from tenant discriminator column
//     11/29/2012-2.5 Guy Pelletier
//       - 395406: Fix nightly static weave test errors
package org.eclipse.persistence.internal.jpa.weaving;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.indirection.ValueHolderInterface;
import org.eclipse.persistence.internal.descriptors.VirtualAttributeMethodInfo;
import org.eclipse.persistence.internal.helper.Helper;
import org.eclipse.persistence.internal.indirection.BasicIndirectionPolicy;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataClass;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataField;
import org.eclipse.persistence.internal.jpa.metadata.accessors.objects.MetadataMethod;
import org.eclipse.persistence.internal.libraries.asm.Type;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.weaving.PersistenceWeavedChangeTracking;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.mappings.ForeignReferenceMapping;
import org.eclipse.persistence.mappings.foundation.AbstractDirectMapping;
import org.eclipse.persistence.sessions.Project;
import org.eclipse.persistence.sessions.Session;

/**
 * This class creates a ClassFileTransformer that is used for dynamic bytecode
 * weaving. It is called by {@link org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl#predeploy}
 * 

* Note: The Session's Project is is scanned to ensure that weaving is * supported and is modified to suit (set the {@link org.eclipse.persistence.descriptors.changetracking.ObjectChangePolicy} * for the Descriptor). */ public class TransformerFactory { public static final String WEAVER_DISABLE_CT_NOT_SUPPORTED = "weaver_change_tracking_disabled_not_supported"; public static final String WEAVER_FOUND_USER_IMPL_CT = "weaver_user_impl_change_tracking"; public static final String WEAVER_NULL_PROJECT = "weaver_null_project"; public static final String WEAVER_DISABLE_BY_SYSPROP = "weaver_disable_by_system_property"; public static final String WEAVER_CLASS_NOT_IN_PROJECT = "weaver_class_not_in_project"; public static final String WEAVER_PROCESSING_CLASS = "weaver_processing_class"; public static final String CANNOT_WEAVE_CHANGETRACKING = "cannot_weave_changetracking"; public static final String CANNOT_WEAVE_VIRTUAL_ONE_TO_ONE = "cannot_weave_virtual_one_to_one"; protected Session session; protected Collection entityClasses; protected Map classDetailsMap; protected ClassLoader classLoader; protected boolean weaveChangeTracking; protected boolean weaveLazy; protected boolean weaveFetchGroups; protected boolean weaveInternal; protected boolean weaveRest; protected boolean weaveMappedSuperClass; public static PersistenceWeaver createTransformerAndModifyProject( Session session, Collection entityClasses, ClassLoader classLoader, boolean weaveLazy, boolean weaveChangeTracking, boolean weaveFetchGroups, boolean weaveInternal, boolean weaveRest, boolean weaveMappedSuperClass) { if (session == null) { throw new IllegalArgumentException("Weaver session cannot be null"); } if (session.getProject() == null) { ((AbstractSession)session).log(SessionLog.SEVERE, SessionLog.WEAVER, WEAVER_NULL_PROJECT, null); throw new IllegalArgumentException("Weaver session's project cannot be null"); } TransformerFactory tf = new TransformerFactory(session, entityClasses, classLoader, weaveLazy, weaveChangeTracking, weaveFetchGroups, weaveInternal, weaveRest, weaveMappedSuperClass); tf.buildClassDetailsAndModifyProject(); return tf.buildPersistenceWeaver(); } public TransformerFactory(Session session, Collection entityClasses, ClassLoader classLoader, boolean weaveLazy, boolean weaveChangeTracking, boolean weaveFetchGroups, boolean weaveInternal, boolean weaveRest, boolean weaveMappedSuperClass) { this.session = session; this.entityClasses = entityClasses; this.classLoader = classLoader; this.classDetailsMap = new HashMap(); this.weaveLazy = weaveLazy; this.weaveChangeTracking = weaveChangeTracking; this.weaveFetchGroups = weaveFetchGroups; this.weaveInternal = weaveInternal; this.weaveRest = weaveRest; this.weaveMappedSuperClass = weaveMappedSuperClass; } /** * INTERNAL: * Look higher in the hierarchy for the mappings listed in the unMappedAttribute list. * * We assume that if a mapping exists, the attribute must either be mapped from the owning * class or from a superclass. */ public void addClassDetailsForMappedSuperClasses(MetadataClass clz, ClassDescriptor initialDescriptor, ClassDetails classDetails, Map classDetailsMap, List unMappedAttributes, boolean weaveChangeTracking){ MetadataClass superClz = clz.getSuperclass(); if (superClz == null || superClz.isObject()){ return; } ClassDescriptor mappedSuperclassDescriptor = ((AbstractSession) session).getMappedSuperclass(superClz.getName()); if (mappedSuperclassDescriptor == null) { ClassDescriptor descriptor = findDescriptor(session.getProject(), clz.getSuperclass().getName()); if (descriptor != null) { return; } } boolean weaveValueHolders = canWeaveValueHolders(superClz, unMappedAttributes); List stillUnMappedMappings = null; ClassDetails superClassDetails = createClassDetails(superClz, weaveValueHolders, weaveChangeTracking, weaveFetchGroups, weaveInternal, weaveRest); superClassDetails.setIsMappedSuperClass(true); if (mappedSuperclassDescriptor != null && ! mappedSuperclassDescriptor.usesPropertyAccessForWeaving()) { superClassDetails.useAttributeAccess(); } else if (!initialDescriptor.usesPropertyAccessForWeaving()){ superClassDetails.useAttributeAccess(); } if (!classDetailsMap.containsKey(superClassDetails.getClassName())){ stillUnMappedMappings = storeAttributeMappings(superClz, superClassDetails, unMappedAttributes, weaveValueHolders); classDetailsMap.put(superClassDetails.getClassName() ,superClassDetails); addClassDetailsForMappedSuperClasses(superClz, initialDescriptor, classDetails, classDetailsMap, stillUnMappedMappings, weaveChangeTracking); } } public PersistenceWeaver buildPersistenceWeaver() { return new PersistenceWeaver(classDetailsMap); } /** * Build a list ClassDetails instance that contains a ClassDetails for each class * in our entities list. */ public void buildClassDetailsAndModifyProject() { if (entityClasses != null && entityClasses.size() > 0) { // scan thru list building details of persistent classes for (MetadataClass metaClass : entityClasses) { // check to ensure that class is present in project // this will be a relational descriptor because MetadataClass only describes relational descriptors boolean isMappedSuperclass = false; ClassDescriptor descriptor = findDescriptor(session.getProject(), metaClass.getName()); if (descriptor == null) { if (weaveMappedSuperClass) { //Bug #466271 - find mapped superclasses which have no implementation descriptor = session.getProject().getMappedSuperclass(metaClass.getName()); if (descriptor == null) { log(SessionLog.FINER, WEAVER_CLASS_NOT_IN_PROJECT, new Object[]{metaClass.getName()}); continue; } else { isMappedSuperclass = true; } } else { log(SessionLog.FINER, WEAVER_CLASS_NOT_IN_PROJECT, new Object[]{metaClass.getName()}); continue; } } log(SessionLog.FINER, WEAVER_PROCESSING_CLASS, new Object[]{metaClass.getName()}); boolean weaveValueHoldersForClass = weaveLazy && canWeaveValueHolders(metaClass, descriptor.getMappings()); boolean weaveChangeTrackingForClass = canChangeTrackingBeEnabled(descriptor, metaClass, weaveChangeTracking); ClassDetails classDetails = createClassDetails(metaClass, weaveValueHoldersForClass, weaveChangeTrackingForClass, weaveFetchGroups, weaveInternal, weaveRest); classDetails.setIsMappedSuperClass(isMappedSuperclass); if (descriptor.isDescriptorTypeAggregate()) { classDetails.setIsEmbedable(true); // classDetails.setShouldWeaveFetchGroups(false); } if (!descriptor.usesPropertyAccessForWeaving()){ classDetails.useAttributeAccess(); } classDetails.getVirtualAccessMethods().addAll(descriptor.getVirtualAttributeMethods()); List unMappedAttributes = storeAttributeMappings(metaClass, classDetails, descriptor.getMappings(), weaveValueHoldersForClass); classDetailsMap.put(classDetails.getClassName() ,classDetails); classDetails.setShouldWeaveConstructorOptimization((classDetails.getDescribedClass().getFields().size() - (descriptor.getMappings().size() - unMappedAttributes.size()))<=0); if (classDetails.getSuperClassName() != null) { addClassDetailsForMappedSuperClasses(metaClass, descriptor, classDetails, classDetailsMap, unMappedAttributes, weaveChangeTracking); } } // hookup superClassDetails for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) { ClassDetails classDetails = (ClassDetails)i.next(); ClassDetails superClassDetails = classDetailsMap.get(classDetails.getSuperClassName()); if (superClassDetails == null) { ClassDescriptor descriptor = findDescriptor(session.getProject(), classDetails.getDescribedClass().getName()); if (descriptor != null && descriptor.hasInheritance()){ superClassDetails = classDetailsMap.get(descriptor.getInheritancePolicy().getParentClassName()); } } if (superClassDetails != null) { classDetails.setSuperClassDetails(superClassDetails); } } // Fix weaveChangeTracking based on superclasses, // we should only weave change tracking if our whole hierarchy can. for (Iterator i = classDetailsMap.values().iterator(); i.hasNext();) { ClassDetails classDetails = (ClassDetails)i.next(); classDetails.setShouldWeaveChangeTracking(classDetails.canWeaveChangeTracking()); } } } /** * Check to ensure the class meets all the conditions necessary to enable change tracking * This could occur either if the class already has change tracking implemented or if the * class is capable of having change tracking woven based on the descriptor. */ protected boolean canChangeTrackingBeEnabled(ClassDescriptor descriptor, MetadataClass clz, boolean globalWeaveChangeTracking) { if (!globalWeaveChangeTracking) { return false; } // If the descriptor was configured to not use change tracking then disable it, also enable if configure explictly. if (descriptor.getObjectChangePolicyInternal() != null) { if (descriptor.getObjectChangePolicyInternal().isDeferredChangeDetectionPolicy()) { return false; } else if (descriptor.getObjectChangePolicyInternal().isObjectChangeTrackingPolicy()) { // Include object and attribute. return true; } } boolean canWeaveChangeTracking = descriptor.supportsChangeTracking(session.getProject()); if (!canWeaveChangeTracking) { log(SessionLog.CONFIG, CANNOT_WEAVE_CHANGETRACKING, new Object[]{descriptor.getJavaClassName()}); } return canWeaveChangeTracking; } protected boolean wasChangeTrackingAlreadyWeaved(Class clz){ Class[] interfaces = clz.getInterfaces(); for (int i = 0; i < interfaces.length; i++) { Class c = interfaces[i]; if (c.getName().equals(PersistenceWeavedChangeTracking.class.getName())){ return true; } } return false; } /** * Determine if value holders are required to be weaved into the class. */ protected boolean canWeaveValueHolders(MetadataClass clz, List mappings) { // we intend to change to fetch=LAZY 1:1 attributes to ValueHolders boolean weaveValueHolders = false; for (Iterator iterator = mappings.iterator(); iterator.hasNext();) { DatabaseMapping mapping = (DatabaseMapping)iterator.next(); String attributeName = mapping.getAttributeName(); if (mapping.isForeignReferenceMapping()) { ForeignReferenceMapping foreignReferenceMapping = (ForeignReferenceMapping)mapping; MetadataClass typeClass = getAttributeTypeFromClass(clz, attributeName, foreignReferenceMapping, true); if ((foreignReferenceMapping.getIndirectionPolicy() instanceof BasicIndirectionPolicy) && (typeClass != null) && (!typeClass.extendsInterface(ValueHolderInterface.class))) { weaveValueHolders = true; } } } return weaveValueHolders; } private ClassDetails createClassDetails(MetadataClass metadataClass, boolean weaveValueHolders, boolean weaveChangeTracking, boolean weaveFetchGroups, boolean weaveInternal, boolean weaveRest) { // compose className in JVM 'slash' format // instead of regular Java 'dotted' format String className = Helper.toSlashedClassName(metadataClass.getName()); String superClassName = Helper.toSlashedClassName(metadataClass.getSuperclass().getName()); ClassDetails classDetails = new ClassDetails(); classDetails.setDescribedClass(metadataClass); classDetails.setClassName(className); classDetails.setSuperClassName(superClassName); classDetails.setShouldWeaveValueHolders(weaveValueHolders); classDetails.setShouldWeaveChangeTracking(weaveChangeTracking); classDetails.setShouldWeaveFetchGroups(weaveFetchGroups); classDetails.setShouldWeaveInternal(weaveInternal); classDetails.setShouldWeaveREST(weaveRest); MetadataMethod method = metadataClass.getMethod("clone", new ArrayList(), false); classDetails.setImplementsCloneMethod(method != null); return classDetails; } /** * Find a descriptor by name in the given project * used to avoid referring to descriptors by class. * This avoids having to construct a project by class facilitating weaving */ protected ClassDescriptor findDescriptor(Project project, String className){ Iterator iterator = project.getOrderedDescriptors().iterator(); while (iterator.hasNext()){ ClassDescriptor descriptor = (ClassDescriptor)iterator.next(); if (descriptor.getJavaClassName().equals(className)){ return descriptor; } } return null; } /** * Return if the class contains the field. */ protected boolean hasFieldInClass(MetadataClass metadataClass, String attributeName) { return metadataClass.getField(attributeName) != null; } /** * Return the class which is the source of the attribute. * i.e. the class that defines the attribute in its class file. */ private MetadataClass getAttributeDeclaringClass(MetadataClass metadataClass, String attributeName) { MetadataField field = metadataClass.getField(attributeName); return field.getDeclaringClass(); } /** * Use the database mapping for an attribute to find it's type. The type returned will either be * the field type of the field in the object or the type returned by the getter method. */ private MetadataClass getAttributeTypeFromClass(MetadataClass metadataClass, String attributeName, DatabaseMapping mapping, boolean checkSuperclass){ String getterMethod = mapping.getGetMethodName(); if (mapping.isAbstractDirectMapping() && mapping.getAttributeAccessor().isVirtualAttributeAccessor()){ return metadataClass.getMetadataClass(((AbstractDirectMapping)mapping).getAttributeClassificationName()); } else if (getterMethod != null) { MetadataMethod method = metadataClass.getMethod(getterMethod, new ArrayList(), checkSuperclass); if (method == null) { return null; } return method.getMetadataClass(method.getReturnType()); } else { MetadataField field = metadataClass.getField(attributeName, checkSuperclass); if (field == null) { return null; } return field.getMetadataClass(field.getType()); } } /** * INTERNAL: * Store a set of attribute mappings on the given ClassDetails that correspond to the given class. * Return the list of mappings that is not specifically found on the given class. These attributes will * be found on MappedSuperclasses. */ protected List storeAttributeMappings(MetadataClass metadataClass, ClassDetails classDetails, List mappings, boolean weaveValueHolders) { List unMappedAttributes = new ArrayList(); Map attributesMap = new HashMap(); Map settersMap = new HashMap(); Map gettersMap = new HashMap(); for (Iterator iterator = mappings.iterator(); iterator.hasNext();) { DatabaseMapping mapping = (DatabaseMapping)iterator.next(); // Can't weave something that isn't really there and not going to be there. if (mapping.isMultitenantPrimaryKeyMapping()) { continue; } String attribute = mapping.getAttributeName(); AttributeDetails attributeDetails = new AttributeDetails(attribute, mapping); if (mapping.getAttributeAccessor().isVirtualAttributeAccessor()){ attributeDetails.setVirtualProperty(mapping.getAttributeAccessor().isVirtualAttributeAccessor()); if ((classDetails.getInfoForVirtualGetMethod(mapping.getGetMethodName()) == null) && (classDetails.getInfoForVirtualSetMethod(mapping.getSetMethodName()) == null)){ VirtualAttributeMethodInfo info = new VirtualAttributeMethodInfo(mapping.getGetMethodName(), mapping.getSetMethodName()); classDetails.getVirtualAccessMethods().add(info); } } // Initial look for the type of this attribute. MetadataClass typeClass = getAttributeTypeFromClass(metadataClass, attribute, mapping, false); if (typeClass == null) { attributeDetails.setAttributeOnSuperClass(true); unMappedAttributes.add(mapping); } // Set the getter and setter method names if the mapping uses property access. if (mapping.getGetMethodName() != null) { gettersMap.put(mapping.getGetMethodName(), attributeDetails); attributeDetails.setGetterMethodName(mapping.getGetMethodName()); if (mapping.getSetMethodName() != null) { settersMap.put(mapping.getSetMethodName(), attributeDetails); attributeDetails.setSetterMethodName(mapping.getSetMethodName()); } if (mapping.isForeignReferenceMapping() && ((ForeignReferenceMapping) mapping).requiresTransientWeavedFields()) { attributeDetails.setWeaveTransientFieldValueHolders(); } // If the property has a matching field, then weave it instead (unless internal weaving is disabled). if (this.weaveInternal) { attributeDetails.setHasField(hasFieldInClass(metadataClass, attribute)); } } else { attributeDetails.setHasField(true); } // If the attribute has a field, then the weaver needs to know in which class it was defined. if (attributeDetails.hasField()) { attributeDetails.setDeclaringType(Type.getType(getAttributeDeclaringClass(metadataClass, attribute).getTypeName())); } // Check for lazy/value-holder indirection. if (mapping.isForeignReferenceMapping()) { ForeignReferenceMapping foreignReferenceMapping = (ForeignReferenceMapping)mapping; // repopulate the reference class with the target of this mapping attributeDetails.setReferenceClassName(foreignReferenceMapping.getReferenceClassName()); if (attributeDetails.getReferenceClassName() != null) { MetadataClass referenceClass = metadataClass.getMetadataFactory().getMetadataClass(attributeDetails.getReferenceClassName()); attributeDetails.setReferenceClassType(Type.getType(referenceClass.getTypeName())); } // This time, look up the type class and include the superclass so we can check for lazy. if (typeClass == null){ typeClass = getAttributeTypeFromClass(metadataClass, attribute, foreignReferenceMapping, true); } if (weaveValueHolders && (foreignReferenceMapping.getIndirectionPolicy() instanceof BasicIndirectionPolicy) && (typeClass != null) && (!typeClass.extendsInterface(ValueHolderInterface.class))) { if (mapping.isObjectReferenceMapping() && attributeDetails.isVirtualProperty()){ classDetails.setShouldWeaveValueHolders(false); log(SessionLog.WARNING, CANNOT_WEAVE_VIRTUAL_ONE_TO_ONE, new Object[]{classDetails.getClassName(), attributeDetails.getAttributeName()}); } else { attributeDetails.weaveVH(weaveValueHolders, foreignReferenceMapping); } } } if (attributeDetails.getReferenceClassType() == null){ if (typeClass == null){ typeClass = getAttributeTypeFromClass(metadataClass, attribute, mapping, true); } } if (typeClass != null) { attributeDetails.setReferenceClassName(typeClass.getName()); attributeDetails.setReferenceClassType(Type.getType(typeClass.getTypeName())); } attributesMap.put(attribute, attributeDetails); } classDetails.setAttributesMap(attributesMap); classDetails.setGetterMethodToAttributeDetails(gettersMap); classDetails.setSetterMethodToAttributeDetails(settersMap); return unMappedAttributes; } protected void log(int level, String msg, Object[] params) { ((org.eclipse.persistence.internal.sessions.AbstractSession)session).log(level, SessionLog.WEAVER, msg, params); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy