You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/05/05 02:56:22 UTC
svn commit: r399903 - in /incubator/cayenne/jpa/trunk/cayenne-jpa/src:
main/java/net/ main/java/net/sf/ main/java/net/sf/cglib/
main/java/org/apache/cayenne/jpa/cspi/
main/java/org/apache/cayenne/jpa/enhancer/
main/java/org/apache/cayenne/jpa/map/ test...
Author: aadamchik
Date: Thu May 4 17:56:21 2006
New Revision: 399903
URL: http://svn.apache.org/viewcvs?rev=399903&view=rev
Log:
a placeholder for method enhancer
Added:
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/net/
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/net/sf/
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/net/sf/cglib/
Modified:
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/cspi/CjpaPersistenceProvider.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/CglibEnhancer.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectAccessorInjector.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectDelegate.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/InterfaceMethodInjector.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/UnitClassTranformer.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaEntityMap.java
incubator/cayenne/jpa/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/enhancer/EnhancerTest.java
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/cspi/CjpaPersistenceProvider.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/cspi/CjpaPersistenceProvider.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/cspi/CjpaPersistenceProvider.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/cspi/CjpaPersistenceProvider.java Thu May 4 17:56:21 2006
@@ -19,6 +19,7 @@
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
+import java.util.Map;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceUnitInfo;
@@ -30,6 +31,7 @@
import org.apache.cayenne.jpa.conf.EntityMapLoaderContext;
import org.apache.cayenne.jpa.enhancer.CglibEnhancer;
import org.apache.cayenne.jpa.enhancer.UnitClassTranformer;
+import org.apache.cayenne.jpa.map.JpaClassDescriptor;
import org.apache.cayenne.jpa.spi.JpaPersistenceProvider;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -117,9 +119,12 @@
// we must set enhancer in this exact place, between JPA and Cayenne mapping
// loading. By now all the JpaEntities are loaded (using separate unit class
// loader) and Cayenne mapping will be using the App ClassLoader.
+ Map<String, JpaClassDescriptor> managedClasses = loader
+ .getEntityMap()
+ .getMangedClasses();
info.addTransformer(new UnitClassTranformer(
- loader.getEntityMap(),
- new CglibEnhancer()));
+ managedClasses,
+ new CglibEnhancer(managedClasses)));
DataMapConverter converter = new DataMapConverter();
DataMap cayenneMap = converter.toDataMap(name, loader.getContext());
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/CglibEnhancer.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/CglibEnhancer.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/CglibEnhancer.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/CglibEnhancer.java Thu May 4 17:56:21 2006
@@ -16,21 +16,27 @@
package org.apache.cayenne.jpa.enhancer;
import java.lang.instrument.IllegalClassFormatException;
+import java.lang.reflect.Method;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Map;
import net.sf.cglib.asm.Attribute;
import net.sf.cglib.asm.ClassReader;
import net.sf.cglib.asm.ClassWriter;
+import net.sf.cglib.asm.Type;
import net.sf.cglib.asm.attrs.Attributes;
import net.sf.cglib.core.ClassGenerator;
+import net.sf.cglib.core.Constants;
import net.sf.cglib.core.DebuggingClassWriter;
+import net.sf.cglib.core.Signature;
import net.sf.cglib.transform.ClassReaderGenerator;
import net.sf.cglib.transform.ClassTransformer;
import net.sf.cglib.transform.ClassTransformerChain;
import net.sf.cglib.transform.TransformingClassGenerator;
+import org.apache.cayenne.jpa.map.JpaClassDescriptor;
import org.objectstyle.cayenne.CayenneRuntimeException;
import org.objectstyle.cayenne.DataObject;
@@ -41,6 +47,29 @@
*/
public class CglibEnhancer implements javax.persistence.spi.ClassTransformer {
+ protected Map<String, JpaClassDescriptor> managedClasses;
+
+ static Signature compileSignature(Method method) {
+
+ Class[] params = method.getParameterTypes();
+ Type[] types;
+ if (params.length == 0) {
+ types = Constants.TYPES_EMPTY;
+ }
+ else {
+ types = new Type[params.length];
+ for (int i = 0; i < params.length; i++) {
+ types[i] = Type.getType(params[i]);
+ }
+ }
+
+ return new Signature(method.getName(), Type.getReturnType(method), types);
+ }
+
+ public CglibEnhancer(Map<String, JpaClassDescriptor> managedClasses) {
+ this.managedClasses = managedClasses;
+ }
+
public byte[] transform(
ClassLoader loader,
String className,
@@ -92,9 +121,10 @@
DataObject.class,
DataObjectDelegate.class,
excludes);
+ ClassTransformer t3 = new DataObjectAccessorInjector(managedClasses);
return new ClassTransformerChain(new ClassTransformer[] {
- t1, t2
+ t1, t2, t3
});
}
}
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectAccessorInjector.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectAccessorInjector.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectAccessorInjector.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectAccessorInjector.java Thu May 4 17:56:21 2006
@@ -15,12 +15,20 @@
*/
package org.apache.cayenne.jpa.enhancer;
+import java.util.Map;
+
import net.sf.cglib.asm.Attribute;
import net.sf.cglib.asm.Type;
import net.sf.cglib.core.CodeEmitter;
+import net.sf.cglib.core.Constants;
import net.sf.cglib.core.Signature;
import net.sf.cglib.transform.ClassEmitterTransformer;
+import org.apache.cayenne.jpa.JpaProviderException;
+import org.apache.cayenne.jpa.map.JpaClassDescriptor;
+import org.apache.cayenne.jpa.map.JpaPropertyDescriptor;
+import org.objectstyle.cayenne.Persistent;
+
/**
* Injects persistence code to the property accessors.
*
@@ -28,12 +36,104 @@
*/
public class DataObjectAccessorInjector extends ClassEmitterTransformer {
+ protected Map<String, JpaClassDescriptor> managedClasses;
+ protected Type staticDelegate;
+ protected Signature getterBeforeSignature;
+ protected Signature setterBeforeSignature;
+ protected Signature setterAfterSignature;
+
+ public DataObjectAccessorInjector(Map<String, JpaClassDescriptor> managedClasses) {
+ this.managedClasses = managedClasses;
+
+ Class delegateClass = DataObjectDelegate.class;
+ this.staticDelegate = Type.getType(delegateClass);
+
+ try {
+ this.getterBeforeSignature = CglibEnhancer.compileSignature(delegateClass
+ .getDeclaredMethod(
+ "beforeGetProperty",
+ Persistent.class,
+ String.class));
+ this.setterBeforeSignature = CglibEnhancer.compileSignature(delegateClass
+ .getDeclaredMethod(
+ "beforeSetProperty",
+ Persistent.class,
+ String.class));
+ this.setterAfterSignature = CglibEnhancer.compileSignature(delegateClass
+ .getDeclaredMethod(
+ "afterSetProperty",
+ Persistent.class,
+ String.class,
+ Object.class,
+ Object.class));
+ }
+ catch (Exception e) {
+ throw new JpaProviderException("Error reflecting delegate methods", e);
+ }
+ }
+
@Override
public CodeEmitter begin_method(
int access,
Signature sig,
Type[] exceptions,
Attribute attrs) {
+
+ if (sig.equals(Constants.SIG_STATIC)) {
+ return super.begin_method(access, sig, exceptions, attrs);
+ }
+
+ String propertyName = JpaClassDescriptor.propertyNameForGetter(sig.getName());
+ if (propertyName != null) {
+ JpaPropertyDescriptor property = getProperty(propertyName);
+
+ if (property != null) {
+ return enhanceGetter(property, access, sig, exceptions, attrs);
+ }
+ }
+ else {
+ propertyName = JpaClassDescriptor.propertyNameForSetter(sig.getName());
+ if (propertyName != null) {
+ JpaPropertyDescriptor property = getProperty(propertyName);
+ if (property != null) {
+ return enhanceSetter(property, access, sig, exceptions, attrs);
+ }
+ }
+ }
+
+ return super.begin_method(access, sig, exceptions, attrs);
+ }
+
+ protected JpaPropertyDescriptor getProperty(String propertyName) {
+ String className = getClassType().getClassName();
+ JpaClassDescriptor descriptor = managedClasses.get(className);
+
+ if (descriptor == null) {
+ throw new JpaProviderException("No descriptor for class: " + className);
+ }
+
+ return descriptor.getProperty(propertyName);
+ }
+
+ protected CodeEmitter enhanceGetter(
+ JpaPropertyDescriptor property,
+ int access,
+ Signature sig,
+ Type[] exceptions,
+ Attribute attrs) {
+
+ // TODO: andrus 5/4/2006 - how can we do that?
+ return super.begin_method(access, sig, exceptions, attrs);
+ }
+
+ protected CodeEmitter enhanceSetter(
+ JpaPropertyDescriptor property,
+ int access,
+ Signature sig,
+ Type[] exceptions,
+ Attribute attrs) {
+
+ // TODO: andrus 5/4/2006 - how can we do that?
return super.begin_method(access, sig, exceptions, attrs);
}
}
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectDelegate.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectDelegate.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectDelegate.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/DataObjectDelegate.java Thu May 4 17:56:21 2006
@@ -24,6 +24,7 @@
import org.objectstyle.cayenne.DataObject;
import org.objectstyle.cayenne.ObjectContext;
import org.objectstyle.cayenne.ObjectId;
+import org.objectstyle.cayenne.Persistent;
import org.objectstyle.cayenne.access.DataContext;
import org.objectstyle.cayenne.access.DataNode;
import org.objectstyle.cayenne.access.types.ExtendedTypeMap;
@@ -52,6 +53,32 @@
// TODO: andrus, 5/2/2006 - going ahead, the delegate should only impement the validation
// methods, as property access by the framework should be done via ClassDescriptor.
public final class DataObjectDelegate {
+
+ public static void beforeGetProperty(Persistent object, String propertyName) {
+ ObjectContext context = object.getObjectContext();
+ if (context != null) {
+ context.prepareForAccess(object, propertyName);
+ }
+ }
+
+ public static void beforeSetProperty(Persistent object, String propertyName) {
+ ObjectContext context = object.getObjectContext();
+ if (context != null) {
+ context.prepareForAccess(object, propertyName);
+ }
+ }
+
+ public static void afterSetProperty(
+ Persistent object,
+ String propertyName,
+ Object oldValue,
+ Object newValue) {
+
+ ObjectContext context = object.getObjectContext();
+ if (context != null) {
+ context.propertyChanged(object, propertyName, oldValue, newValue);
+ }
+ }
public static DataContext getDataContext(DataObject object) {
ObjectContext context = object.getObjectContext();
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/InterfaceMethodInjector.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/InterfaceMethodInjector.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/InterfaceMethodInjector.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/InterfaceMethodInjector.java Thu May 4 17:56:21 2006
@@ -45,6 +45,8 @@
protected List<Signature> interfaceMethods;
protected List<Signature> delegateMethods;
+
+
public InterfaceMethodInjector(Class delegatedInterface, Class staticDelegate,
Collection<String> excludedMethods) {
this.staticDelegate = Type.getType(staticDelegate);
@@ -56,7 +58,7 @@
for (Method m : methods) {
if (!excludedMethods.contains(m.getName())) {
- interfaceMethods.add(compileSignature(m));
+ interfaceMethods.add(CglibEnhancer.compileSignature(m));
delegateMethods.add(mapDelegateMethod(staticDelegate, m));
}
}
@@ -119,24 +121,7 @@
+ "'");
}
- return compileSignature(delegateMethod);
- }
-
- protected Signature compileSignature(Method method) {
-
- Class[] params = method.getParameterTypes();
- Type[] types;
- if (params.length == 0) {
- types = Constants.TYPES_EMPTY;
- }
- else {
- types = new Type[params.length];
- for (int i = 0; i < params.length; i++) {
- types[i] = Type.getType(params[i]);
- }
- }
-
- return new Signature(method.getName(), Type.getReturnType(method), types);
+ return CglibEnhancer.compileSignature(delegateMethod);
}
/**
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/UnitClassTranformer.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/UnitClassTranformer.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/UnitClassTranformer.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/enhancer/UnitClassTranformer.java Thu May 4 17:56:21 2006
@@ -17,14 +17,11 @@
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.Map;
import javax.persistence.spi.ClassTransformer;
-import org.apache.cayenne.jpa.map.JpaEntity;
-import org.apache.cayenne.jpa.map.JpaEntityMap;
-import org.apache.cayenne.jpa.map.JpaMappedSuperclass;
+import org.apache.cayenne.jpa.map.JpaClassDescriptor;
/**
* A ClassTransformer decorator that passes through classes mentioned in the JpaEntityMap
@@ -35,21 +32,12 @@
public class UnitClassTranformer implements ClassTransformer {
protected ClassTransformer transformer;
- protected Set<String> managedClasses;
+ protected Map<String, JpaClassDescriptor> managedClasses;
- public UnitClassTranformer(JpaEntityMap entityMap, ClassTransformer transformer) {
+ public UnitClassTranformer(Map<String, JpaClassDescriptor> managedClasses,
+ ClassTransformer transformer) {
this.transformer = transformer;
- this.managedClasses = new HashSet<String>();
-
- for (JpaMappedSuperclass entity : entityMap.getMappedSuperclasses()) {
- managedClasses.add(entity.getClassName().replace('.', '/'));
- }
-
- for (JpaEntity entity : entityMap.getEntities()) {
- // TODO: andrus, 5/1/2006 - need not enhance entities extending mapped
- // superclasses
- managedClasses.add(entity.getClassName().replace('.', '/'));
- }
+ this.managedClasses = managedClasses;
}
public byte[] transform(
@@ -58,6 +46,7 @@
Class<?> classBeingRedefined,
ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
+
return isManagedClass(className) ? transformer.transform(
loader,
className,
@@ -71,6 +60,6 @@
* expected in the internal format, separated by "/", not ".".
*/
protected boolean isManagedClass(String className) {
- return managedClasses.contains(className);
+ return managedClasses.containsKey(className.replace('/', '.'));
}
}
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaEntityMap.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaEntityMap.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaEntityMap.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/main/java/org/apache/cayenne/jpa/map/JpaEntityMap.java Thu May 4 17:56:21 2006
@@ -17,6 +17,8 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import javax.persistence.CascadeType;
import javax.persistence.FlushModeType;
@@ -48,6 +50,39 @@
protected Collection<JpaTableGenerator> tableGenerators;
protected JpaEntityListeners defaultEntityListeners;
protected Collection<CascadeType> cascades;
+
+ /**
+ * Compiles and returns a map of managed class descriptors that includes descriptors
+ * for entities, managed superclasses and embeddables. Note that class name key in the
+ * map uses slashes, not dots, to separate package components.
+ */
+ public Map<String, JpaClassDescriptor> getMangedClasses() {
+ Map<String, JpaClassDescriptor> managedClasses = new HashMap<String, JpaClassDescriptor>();
+
+ if (mappedSuperclasses != null) {
+ for (JpaMappedSuperclass object : mappedSuperclasses) {
+ managedClasses.put(object.getClassName(), object.getClassDescriptor());
+ }
+ }
+
+ if (entities != null) {
+ for (JpaEntity object : entities) {
+ // TODO: andrus, 5/1/2006 - need not enhance entities extending mapped
+ // superclasses
+ managedClasses.put(object.getClassName(), object.getClassDescriptor());
+ }
+ }
+
+ if (embeddables != null) {
+ for (JpaEmbeddable object : embeddables) {
+ // TODO: andrus, 5/1/2006 - need not enhance entities extending mapped
+ // superclasses
+ managedClasses.put(object.getClassName(), object.getClassDescriptor());
+ }
+ }
+
+ return managedClasses;
+ }
/**
* Returns a JpaEntity describing a given persistent class.
Modified: incubator/cayenne/jpa/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/enhancer/EnhancerTest.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/jpa/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/enhancer/EnhancerTest.java?rev=399903&r1=399902&r2=399903&view=diff
==============================================================================
--- incubator/cayenne/jpa/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/enhancer/EnhancerTest.java (original)
+++ incubator/cayenne/jpa/trunk/cayenne-jpa/src/test/java/org/apache/cayenne/jpa/enhancer/EnhancerTest.java Thu May 4 17:56:21 2006
@@ -19,9 +19,15 @@
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
import junit.framework.TestCase;
+import org.apache.cayenne.jpa.map.AccessType;
+import org.apache.cayenne.jpa.map.JpaClassDescriptor;
+import org.apache.cayenne.jpa.map.JpaEntityMap;
+import org.apache.cayenne.jpa.spi.JpaUnitClassLoader;
import org.objectstyle.cayenne.DataObject;
import org.objectstyle.cayenne.ObjectId;
import org.objectstyle.cayenne.PersistenceState;
@@ -43,8 +49,21 @@
managedClasses.add(E2);
managedClasses.add(ET1);
managedClasses.add(ET2);
+
+ JpaEntityMap entityMap = new JpaEntityMap();
+ entityMap.setAccess(AccessType.FIELD);
+
+ ClassLoader helper = new JpaUnitClassLoader(Thread
+ .currentThread()
+ .getContextClassLoader());
+
+ Map<String, JpaClassDescriptor> map = new HashMap<String, JpaClassDescriptor>();
+ map.put(E1, new JpaClassDescriptor(entityMap, Class.forName(E1, true, helper)));
+ map.put(E2, new JpaClassDescriptor(entityMap, Class.forName(E2, true, helper)));
+ map.put(ET1, new JpaClassDescriptor(entityMap, Class.forName(ET1, true, helper)));
+ map.put(ET2, new JpaClassDescriptor(entityMap, Class.forName(ET2, true, helper)));
- loader = new EnhancingClassLoader(new CglibEnhancer(), managedClasses);
+ loader = new EnhancingClassLoader(new CglibEnhancer(map), managedClasses);
}
public void testClassLoading() throws Exception {