Author: aadamchik
Date: Mon Oct 9 20:13:17 2006
New Revision: 454589
URL: http://svn.apache.org/viewvc?view=rev&rev=454589
Log:
implementing Persistence interface properties injection
Added:
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
Removed:
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/EnhancedPojoDescriptor.java
Modified:
incubator/cayenne/sandbox/asm-enhancer/.classpath
incubator/cayenne/sandbox/asm-enhancer/pom.xml
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/AsmEnhancerTest.java
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
Modified: incubator/cayenne/sandbox/asm-enhancer/.classpath
URL:
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/.classpath?view=diff&rev=454589&r1=454588&r2=454589
==============================================================================
--- incubator/cayenne/sandbox/asm-enhancer/.classpath (original)
+++ incubator/cayenne/sandbox/asm-enhancer/.classpath Mon Oct 9 20:13:17 2006
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
- <classpathentry kind="src" path="src/test/java"/>
- <classpathentry kind="src" path="src/main/java"/>
- <classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
- <classpathentry kind="output" path="target/classes"/>
+ <classpathentry kind="src" path="src/main/java" />
+ <classpathentry kind="src" path="src/test/java" />
+ <classpathentry kind="con"
path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+ <classpathentry kind="con"
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER" />
+ <classpathentry kind="output" path="target/classes" />
</classpath>
Modified: incubator/cayenne/sandbox/asm-enhancer/pom.xml
URL:
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/pom.xml?view=diff&rev=454589&r1=454588&r2=454589
==============================================================================
--- incubator/cayenne/sandbox/asm-enhancer/pom.xml (original)
+++ incubator/cayenne/sandbox/asm-enhancer/pom.xml Mon Oct 9 20:13:17 2006
@@ -47,4 +47,19 @@
<version>3.0-incubating-SNAPSHOT</version>
</dependency>
</dependencies>
+
+ <build>
+ <plugins>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
</project>
Added:
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
URL:
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java?view=auto&rev=454589
==============================================================================
---
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
(added)
+++
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
Mon Oct 9 20:13:17 2006
@@ -0,0 +1,140 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.enhancer;
+
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+/**
+ * A builder that encapsulates common class enhancement operations.
+ *
+ * @author Andrus Adamchik
+ */
+class ClassBuilder {
+
+ private String fieldPrefix = "$cay_";
+ private ClassVisitor classVisitor;
+ private Type currentClass;
+
+ ClassBuilder(ClassVisitor classVisitor) {
+ this.classVisitor = classVisitor;
+ }
+
+ void reset(String className) {
+ // assuming no primitives or arrays
+ this.currentClass = Type.getType("L" + className + ";");
+ }
+
+ void createProperty(Class type, String name) {
+ createProperty(type, name, false);
+ }
+
+ void createProperty(Class type, String name, boolean isTransient) {
+ Type asmType = Type.getType(type);
+
+ int access = Opcodes.ACC_PROTECTED;
+ if (isTransient) {
+ access += Opcodes.ACC_TRANSIENT;
+ }
+
+ createField(name, asmType, access);
+ createGetter(name, asmType);
+ createSetter(name, asmType);
+ }
+
+ private void createSetter(String propertyName, Type asmType) {
+
+ String methodName = "set" +
Character.toUpperCase(propertyName.charAt(0));
+ if (propertyName.length() > 1) {
+ methodName += propertyName.substring(1);
+ }
+
+ MethodVisitor mv = classVisitor.visitMethod(Opcodes.ACC_PUBLIC,
methodName, "("
+ + asmType.getDescriptor()
+ + ")V", null, null);
+ mv.visitCode();
+ Label l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+
+ // TODO: other opcodes
+ if ("I".equals(asmType.getDescriptor())) {
+ mv.visitVarInsn(Opcodes.ILOAD, 1);
+ }
+ else {
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ }
+
+ mv.visitFieldInsn(Opcodes.PUTFIELD, currentClass.getInternalName(),
fieldPrefix
+ + propertyName, asmType.getDescriptor());
+ mv.visitInsn(Opcodes.RETURN);
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+ mv.visitLocalVariable("this", currentClass.getDescriptor(), null, l0,
l1, 0);
+ mv.visitLocalVariable(propertyName, asmType.getDescriptor(), null, l0,
l1, 1);
+ mv.visitMaxs(2, 2);
+ mv.visitEnd();
+ }
+
+ private void createGetter(String propertyName, Type asmType) {
+
+ String prefix = "boolean".equals(asmType.getClassName()) ? "is" :
"get";
+ String methodName = prefix +
Character.toUpperCase(propertyName.charAt(0));
+ if (propertyName.length() > 1) {
+ methodName += propertyName.substring(1);
+ }
+
+ MethodVisitor mv = classVisitor.visitMethod(Opcodes.ACC_PUBLIC,
methodName, "()"
+ + asmType.getDescriptor(), null, null);
+ mv.visitCode();
+ Label l0 = new Label();
+ mv.visitLabel(l0);
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitFieldInsn(Opcodes.GETFIELD, currentClass.getInternalName(),
fieldPrefix
+ + propertyName, asmType.getDescriptor());
+
+ // TODO: other return opcodes
+ if ("I".equals(asmType.getDescriptor())) {
+ mv.visitInsn(Opcodes.IRETURN);
+ }
+ else {
+ mv.visitInsn(Opcodes.ARETURN);
+ }
+
+ Label l1 = new Label();
+ mv.visitLabel(l1);
+ mv.visitLocalVariable("this", currentClass.getDescriptor(), null, l0,
l1, 0);
+ mv.visitMaxs(1, 1);
+ mv.visitEnd();
+ }
+
+ private void createField(String propertyName, Type asmType, int access) {
+ FieldVisitor fv = classVisitor.visitField(
+ access,
+ fieldPrefix + propertyName,
+ asmType.getDescriptor(),
+ null,
+ null);
+ fv.visitEnd();
+ }
+}
Modified:
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
URL:
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java?view=diff&rev=454589&r1=454588&r2=454589
==============================================================================
---
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
(original)
+++
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
Mon Oct 9 20:13:17 2006
@@ -20,12 +20,11 @@
import java.util.Collection;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.ObjectId;
import org.objectweb.asm.ClassAdapter;
import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
/**
* ASM-based visitor that turns a pojo class into enahnced persistent object.
@@ -34,12 +33,13 @@
*/
class PersistentClassVisitor extends ClassAdapter {
- private String className;
private Collection<String> enhancedProperties;
+ private ClassBuilder builder;
PersistentClassVisitor(ClassVisitor visitor, Collection<String>
enhancedProperties) {
super(visitor);
this.enhancedProperties = enhancedProperties;
+ this.builder = new ClassBuilder(this);
}
/**
@@ -54,12 +54,12 @@
String superName,
String[] interfaces) {
- this.className = name;
-
super.visit(version, access, name, signature, superName, interfaces);
- injectPersistenceFields();
- injectPersistenceMethods();
+ builder.reset(name);
+ builder.createProperty(ObjectId.class, "objectId");
+ builder.createProperty(ObjectContext.class, "objectContext", true);
+ builder.createProperty(Integer.TYPE, "persistenceState");
}
/**
@@ -78,67 +78,16 @@
// TODO: andrus, 10/8/2006 - check method sig for real... just checking
// the name is not enough
- String getProperty = EnhancerUtil.propertyNameForGetter(name);
- if (getProperty != null && enhancedProperties.contains(getProperty)) {
- return new PersistentGetterVisitor(mv, className, getProperty);
- }
-
- String setProperty = EnhancerUtil.propertyNameForSetter(name);
- if (setProperty != null && enhancedProperties.contains(setProperty)) {
- return new PersistentSetterVisitor(mv, className, setProperty);
- }
+ // String getProperty = EnhancerUtil.propertyNameForGetter(name);
+ // if (getProperty != null &&
enhancedProperties.contains(getProperty)) {
+ // return new PersistentGetterVisitor(mv, className, getProperty);
+ // }
+ //
+ // String setProperty = EnhancerUtil.propertyNameForSetter(name);
+ // if (setProperty != null &&
enhancedProperties.contains(setProperty)) {
+ // return new PersistentSetterVisitor(mv, className, setProperty);
+ // }
return mv;
- }
-
- private void injectPersistenceFields() {
- FieldVisitor fv = visitField(
- Opcodes.ACC_PROTECTED,
- EnhancedPojoDescriptor.OBJECT_ID_FIELD,
- "Lorg/apache/cayenne/ObjectId;",
- null,
- null);
- fv.visitEnd();
-
- fv = visitField(
- Opcodes.ACC_PROTECTED,
- EnhancedPojoDescriptor.PERSISTENCE_STATE_FIELD,
- "I",
- null,
- null);
- fv.visitEnd();
-
- fv = visitField(
- Opcodes.ACC_PROTECTED + Opcodes.ACC_TRANSIENT,
- EnhancedPojoDescriptor.OBJECT_CONTEXT_FIELD,
- "Lorg/apache/cayenne/ObjectContext;",
- null,
- null);
- fv.visitEnd();
- }
-
- private void injectPersistenceMethods() {
-
- MethodVisitor mv = visitMethod(
- Opcodes.ACC_PUBLIC,
- "getObjectContext",
- "()Lorg/apache/cayenne/ObjectContext;",
- null,
- null);
- mv.visitCode();
- Label l0 = new Label();
- mv.visitLabel(l0);
- mv.visitVarInsn(Opcodes.ALOAD, 0);
- mv.visitFieldInsn(
- Opcodes.GETFIELD,
- className,
- EnhancedPojoDescriptor.OBJECT_CONTEXT_FIELD,
- "Lorg/apache/cayenne/ObjectContext;");
- mv.visitInsn(Opcodes.ARETURN);
- Label l1 = new Label();
- mv.visitLabel(l1);
- mv.visitLocalVariable("this", className, null, l0, l1, 0);
- mv.visitMaxs(1, 1);
- mv.visitEnd();
}
}
Modified:
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/AsmEnhancerTest.java
URL:
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/AsmEnhancerTest.java?view=diff&rev=454589&r1=454588&r2=454589
==============================================================================
---
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/AsmEnhancerTest.java
(original)
+++
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/AsmEnhancerTest.java
Mon Oct 9 20:13:17 2006
@@ -1,6 +1,7 @@
package org.apache.cayenne.enhancer;
import java.lang.reflect.Field;
+import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collection;
@@ -15,7 +16,7 @@
public class AsmEnhancerTest extends TestCase {
- public static final String C1 =
"org.apache.cayenne.jpa.enhancer.MockPojo1";
+ public static final String C1 = "org.apache.cayenne.enhancer.MockPojo1";
protected ClassLoader loader;
@@ -39,27 +40,48 @@
assertNotNull(e1Class);
assertEquals(C1, e1Class.getName());
- Field objectContext = e1Class
- .getDeclaredField(EnhancedPojoDescriptor.OBJECT_CONTEXT_FIELD);
+ Field objectContext = e1Class.getDeclaredField("$cay_objectContext");
assertTrue(ObjectContext.class.isAssignableFrom(objectContext.getType()));
assertTrue(!Modifier.isStatic(objectContext.getModifiers()));
assertTrue(Modifier.isProtected(objectContext.getModifiers()));
assertTrue(!Modifier.isFinal(objectContext.getModifiers()));
assertTrue(Modifier.isTransient(objectContext.getModifiers()));
- Field persistenceState = e1Class
-
.getDeclaredField(EnhancedPojoDescriptor.PERSISTENCE_STATE_FIELD);
+ Field persistenceState =
e1Class.getDeclaredField("$cay_persistenceState");
assertTrue(Integer.TYPE.isAssignableFrom(persistenceState.getType()));
assertTrue(!Modifier.isStatic(persistenceState.getModifiers()));
assertTrue(Modifier.isProtected(persistenceState.getModifiers()));
assertTrue(!Modifier.isFinal(persistenceState.getModifiers()));
assertTrue(!Modifier.isTransient(persistenceState.getModifiers()));
- Field objectId =
e1Class.getDeclaredField(EnhancedPojoDescriptor.OBJECT_ID_FIELD);
+ Field objectId = e1Class.getDeclaredField("$cay_objectId");
assertTrue(ObjectId.class.isAssignableFrom(objectId.getType()));
assertTrue(!Modifier.isStatic(objectId.getModifiers()));
assertTrue(Modifier.isProtected(objectId.getModifiers()));
assertTrue(!Modifier.isFinal(objectId.getModifiers()));
assertTrue(!Modifier.isTransient(objectId.getModifiers()));
+ }
+
+ public void testPersistentPropertiesInjected() throws Exception {
+ Class e1Class = Class.forName(C1, true, loader);
+ assertNotNull(e1Class);
+ assertEquals(C1, e1Class.getName());
+
+ Method getObjectContext = e1Class.getDeclaredMethod(
+ "getObjectContext",
+ (Class[]) null);
+ Method setObjectContext = e1Class.getDeclaredMethod(
+ "setObjectContext",
+ new Class[] {
+ ObjectContext.class
+ });
+
+ Object o = e1Class.newInstance();
+ assertNull(getObjectContext.invoke(o, (Object[]) null));
+ ObjectContext oc = new MockObjectContext();
+ setObjectContext.invoke(o, new Object[] {
+ oc
+ });
+ assertSame(oc, getObjectContext.invoke(o, (Object[]) null));
}
}
Modified:
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
URL:
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java?view=diff&rev=454589&r1=454588&r2=454589
==============================================================================
---
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
(original)
+++
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
Mon Oct 9 20:13:17 2006
@@ -23,6 +23,12 @@
import org.apache.cayenne.PersistenceState;
import org.apache.cayenne.Persistent;
+/**
+ * This class in combination with the ASM Eclipse plugin is used as a
reference for
+ * building parts of the ASM enhancer.
+ *
+ * @author Andrus Adamchik
+ */
public class MockEnhancedPojo implements Persistent {
protected ObjectId $cay_objectId;
@@ -56,10 +62,6 @@
public void setPersistenceState(int persistenceState) {
this.$cay_persistenceState = persistenceState;
-
- if (persistenceState == PersistenceState.TRANSIENT) {
- this.$cay_objectContext = null;
- }
}
public ObjectContext getObjectContext() {