You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by st...@apache.org on 2023/05/06 07:18:34 UTC
[openjpa] 09/17: OPENJPA-2909 generate CalendarProxy via ASM
This is an automated email from the ASF dual-hosted git repository.
struberg pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/openjpa.git
commit 87458c708bc3971763f9dc79153b9ac8aee66c8c
Author: Mark Struberg <st...@apache.org>
AuthorDate: Tue May 2 14:47:16 2023 +0200
OPENJPA-2909 generate CalendarProxy via ASM
---
.../org/apache/openjpa/util/ProxyManagerImpl.java | 301 ++++++++++++---------
1 file changed, 175 insertions(+), 126 deletions(-)
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
index 47f75f9bb..e1a6ce40b 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ProxyManagerImpl.java
@@ -98,6 +98,7 @@ public class ProxyManagerImpl
private static final Localizer _loc = Localizer.forPackage
(ProxyManagerImpl.class);
+ public static final Type TYPE_OBJECT = Type.getType(Object.class);
private static long _proxyId = 0L;
private static final Map _stdCollections = new HashMap();
@@ -469,8 +470,7 @@ public class ProxyManagerImpl
ProxyCalendar.class);
Class pcls = loadBuildTimeProxy(type, l);
if (pcls == null)
- pcls = GeneratedClasses.loadBCClass(
- generateProxyCalendarBytecode(type, true), l);
+ pcls = generateAndLoadProxyCalendar(type, true, l);
proxy = (ProxyCalendar) instantiateProxy(pcls, null, null);
_proxies.put(type, proxy);
}
@@ -676,15 +676,20 @@ public class ProxyManagerImpl
return GeneratedClasses.loadAsmClass(proxyClassName, classBytes, ProxyDate.class, l);
}
+ private Class generateAndLoadProxyCalendar(Class type, boolean runtime, ClassLoader l) {
+ final String proxyClassName = getProxyClassName(type, runtime);
+ final byte[] classBytes = generateProxyCalendarBytecode(type, runtime, proxyClassName);
+
+ return GeneratedClasses.loadAsmClass(proxyClassName, classBytes, ProxyDate.class, l);
+ }
+
/**
* Generate the bytecode for a date proxy for the given type.
*/
protected byte[] generateProxyDateBytecode(Class type, boolean runtime, String proxyClassName) {
assertNotFinal(type);
String proxyClassDef = proxyClassName.replace('.', '/');
-
- String superClassFileNname = type.getName().replace('.', '/');
-
+ String superClassFileNname = Type.getInternalName(type);
String[] interfaceNames = new String[]{Type.getInternalName(ProxyDate.class)};
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
@@ -704,6 +709,34 @@ public class ProxyManagerImpl
return cw.toByteArray();
}
+ /**
+ * Generate the bytecode for a calendar proxy for the given type.
+ */
+ protected byte[] generateProxyCalendarBytecode(Class type, boolean runtime, String proxyClassName) {
+ assertNotFinal(type);
+ String proxyClassDef = proxyClassName.replace('.', '/');
+ String superClassFileNname = Type.getInternalName(type);
+ String[] interfaceNames = new String[]{Type.getInternalName(ProxyCalendar.class)};
+
+ ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+ cw.visit(Opcodes.V11, Opcodes.ACC_PUBLIC + Opcodes.ACC_SUPER, proxyClassDef,
+ null, superClassFileNname, interfaceNames);
+
+ String classFileName = runtime ? type.getName() : proxyClassDef;
+ cw.visitSource(classFileName + ".java", null);
+
+ delegateConstructors(cw, type, superClassFileNname);
+ addInstanceVariables(cw);
+ addProxyMethods(cw, true, proxyClassDef, type);
+ addProxyCalendarMethods(cw, proxyClassDef, type);
+ proxySetters(cw, proxyClassDef, type);
+ addWriteReplaceMethod(cw, proxyClassDef, runtime);
+
+ return cw.toByteArray();
+
+ }
+
+
/**
* add the instance variables to the class to be generated
*/
@@ -808,13 +841,13 @@ public class ProxyManagerImpl
* provide a detached proxy object (null out the StateManager).
*/
MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "clone",
- Type.getMethodDescriptor(Type.getType(Object.class))
+ Type.getMethodDescriptor(TYPE_OBJECT)
, null, null);
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(parentClass), "clone",
- Type.getMethodDescriptor(Type.getType(Object.class)), false);
+ Type.getMethodDescriptor(TYPE_OBJECT), false);
mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Proxy.class));
mv.visitVarInsn(Opcodes.ASTORE, 1);
mv.visitVarInsn(Opcodes.ALOAD, 1);
@@ -886,8 +919,9 @@ public class ProxyManagerImpl
}
MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "copy",
- Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Object.class))
+ Type.getMethodDescriptor(TYPE_OBJECT, TYPE_OBJECT)
, null, null);
+ mv.visitCode();
mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(type));
mv.visitInsn(Opcodes.DUP);
@@ -939,6 +973,7 @@ public class ProxyManagerImpl
MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "newInstance",
Type.getMethodDescriptor(Type.getType(ProxyDate.class))
, null, null);
+ mv.visitCode();
mv.visitTypeInsn(Opcodes.NEW, proxyClassDef);
mv.visitInsn(Opcodes.DUP);
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, proxyClassDef, "<init>",
@@ -950,6 +985,130 @@ public class ProxyManagerImpl
}
}
+ private void addProxyCalendarMethods(ClassWriter cw, String proxyClassDef, Class type) {
+ // calendar copy
+ {
+ Constructor cons = findCopyConstructor(type);
+ Class[] params = (cons == null) ? new Class[0] : cons.getParameterTypes();
+
+ MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "copy",
+ Type.getMethodDescriptor(TYPE_OBJECT, TYPE_OBJECT)
+ , null, null);
+ mv.visitCode();
+
+ mv.visitTypeInsn(Opcodes.NEW, Type.getInternalName(type));
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(type), "<init>",
+ Type.getMethodDescriptor(Type.VOID_TYPE, getParamTypes(params)), false);
+
+ // timeInMillis
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Calendar.class));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Calendar.class), "getTimeInMillis",
+ Type.getMethodDescriptor(Type.LONG_TYPE), false);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(type), "setTimeInMillis",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.LONG_TYPE), false);
+
+ // lenient
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Calendar.class));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Calendar.class), "isLenient",
+ Type.getMethodDescriptor(Type.BOOLEAN_TYPE), false);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(type), "setLenient",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.BOOLEAN_TYPE), false);
+
+ // firstDayOfWeek
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Calendar.class));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Calendar.class), "getFirstDayOfWeek",
+ Type.getMethodDescriptor(Type.INT_TYPE), false);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(type), "setFirstDayOfWeek",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false);
+
+ // minimalDaysInFirstWeek
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Calendar.class));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Calendar.class), "getMinimalDaysInFirstWeek",
+ Type.getMethodDescriptor(Type.INT_TYPE), false);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(type), "setMinimalDaysInFirstWeek",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE), false);
+
+ // timeZone
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Calendar.class));
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(Calendar.class), "getTimeZone",
+ Type.getMethodDescriptor(Type.getType(TimeZone.class)), false);
+ mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, Type.getInternalName(type), "setTimeZone",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(TimeZone.class)), false);
+
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+ }
+
+ // newInstance factory
+ {
+ MethodVisitor mv = cw.visitMethod(Modifier.PUBLIC, "newInstance",
+ Type.getMethodDescriptor(Type.getType(ProxyCalendar.class))
+ , null, null);
+ mv.visitCode();
+ mv.visitTypeInsn(Opcodes.NEW, proxyClassDef);
+ mv.visitInsn(Opcodes.DUP);
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, proxyClassDef, "<init>",
+ Type.getMethodDescriptor(Type.VOID_TYPE), false);
+
+ mv.visitInsn(Opcodes.ARETURN);
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+ }
+
+ // proxy the protected computeFields method b/c it is called on
+ // mutate, and some setters are final and therefore not proxyable
+ {
+ MethodVisitor mv = cw.visitMethod(Modifier.PROTECTED, "computeFields",
+ Type.getMethodDescriptor(Type.VOID_TYPE)
+ , null, null);
+ mv.visitCode();
+
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitInsn(Opcodes.ICONST_1);
+ mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Proxies.class), "dirty",
+ Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(Proxy.class), Type.BOOLEAN_TYPE), false);
+
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(type), "computeFields",
+ Type.getMethodDescriptor(Type.VOID_TYPE), false);
+
+ mv.visitInsn(Opcodes.RETURN);
+ mv.visitMaxs(-1, -1);
+ mv.visitEnd();
+ }
+
+
+ /*
+
+ // proxy the protected computeFields method b/c it is called on
+ // mutate, and some setters are final and therefore not proxyable
+ m = bc.declareMethod("computeFields", void.class, null);
+ m.makeProtected();
+ code = m.getCode(true);
+ code.aload().setThis();
+ code.constant().setValue(true);
+ code.invokestatic().setMethod(Proxies.class, "dirty", void.class,
+ new Class[] { Proxy.class, boolean.class });
+ code.aload().setThis();
+ code.invokespecial().setMethod(type, "computeFields", void.class, null);
+ code.vreturn();
+ code.calculateMaxStack();
+ code.calculateMaxLocals();
+ */
+ }
+
/**
* Proxy setter methods of the given type.
*
@@ -1006,13 +1165,13 @@ public class ProxyManagerImpl
*/
private void addWriteReplaceMethod(ClassWriter cw, String proxyClassDef, boolean runtime) {
MethodVisitor mv = cw.visitMethod(Modifier.PROTECTED, "writeReplace",
- Type.getMethodDescriptor(Type.getType(Object.class))
+ Type.getMethodDescriptor(TYPE_OBJECT)
, null, new String[]{Type.getInternalName(ObjectStreamException.class)});
mv.visitCode();
mv.visitVarInsn(Opcodes.ALOAD, 0);
mv.visitInsn(runtime ? Opcodes.ICONST_0 : Opcodes.ICONST_1); // !runtime
mv.visitMethodInsn(Opcodes.INVOKESTATIC, Type.getInternalName(Proxies.class), "writeReplace",
- Type.getMethodDescriptor(Type.getType(Object.class), Type.getType(Proxy.class), Type.BOOLEAN_TYPE), false);
+ Type.getMethodDescriptor(TYPE_OBJECT, Type.getType(Proxy.class), Type.BOOLEAN_TYPE), false);
mv.visitInsn(Opcodes.ARETURN);
mv.visitMaxs(-1, -1);
@@ -1120,25 +1279,6 @@ public class ProxyManagerImpl
/* ASM end */
- /**
- * Generate the bytecode for a calendar proxy for the given type.
- */
- protected BCClass generateProxyCalendarBytecode(Class type,
- boolean runtime) {
- assertNotFinal(type);
- Project project = new Project();
- BCClass bc = AccessController.doPrivileged(J2DoPrivHelper
- .loadProjectClassAction(project, getProxyClassName(type, runtime)));
- bc.setSuperclass(type);
- bc.declareInterface(ProxyCalendar.class);
-
- delegateConstructors(bc, type);
- addProxyMethods(bc, true);
- addProxyCalendarMethods(bc, type);
- proxySetters(bc, type);
- addWriteReplaceMethod(bc, runtime);
- return bc;
- }
/**
* Generate the bytecode for a bean proxy for the given type.
@@ -1523,100 +1663,7 @@ public class ProxyManagerImpl
code.calculateMaxStack();
code.calculateMaxLocals();
}
-
- /**
- * Implement the methods in the {@link ProxyCalendar} interface.
- */
- private void addProxyCalendarMethods(BCClass bc, Class type) {
- // calendar copy
- Constructor cons = findCopyConstructor(type);
- Class[] params = (cons == null) ? new Class[0]
- : cons.getParameterTypes();
-
- BCMethod m = bc.declareMethod("copy", Object.class,
- new Class[] {Object.class});
- m.makePublic();
- Code code = m.getCode(true);
-
- code.anew().setType(type);
- code.dup();
- if (params.length == 1) {
- code.aload().setParam(0);
- code.checkcast().setType(params[0]);
- }
- code.invokespecial().setMethod(type, "<init>", void.class, params);
- if (params.length == 0) {
- code.dup();
- code.aload().setParam(0);
- code.checkcast().setType(Calendar.class);
- code.invokevirtual().setMethod(Calendar.class, "getTimeInMillis",
- long.class, null);
- code.invokevirtual().setMethod(type, "setTimeInMillis", void.class,
- new Class[] { long.class });
-
- code.dup();
- code.aload().setParam(0);
- code.checkcast().setType(Calendar.class);
- code.invokevirtual().setMethod(Calendar.class, "isLenient",
- boolean.class, null);
- code.invokevirtual().setMethod(type, "setLenient", void.class,
- new Class[] { boolean.class });
-
- code.dup();
- code.aload().setParam(0);
- code.checkcast().setType(Calendar.class);
- code.invokevirtual().setMethod(Calendar.class, "getFirstDayOfWeek",
- int.class, null);
- code.invokevirtual().setMethod(type, "setFirstDayOfWeek",
- void.class, new Class[] { int.class });
-
- code.dup();
- code.aload().setParam(0);
- code.checkcast().setType(Calendar.class);
- code.invokevirtual().setMethod(Calendar.class,
- "getMinimalDaysInFirstWeek", int.class, null);
- code.invokevirtual().setMethod(type, "setMinimalDaysInFirstWeek",
- void.class, new Class[] { int.class });
-
- code.dup();
- code.aload().setParam(0);
- code.checkcast().setType(Calendar.class);
- code.invokevirtual().setMethod(Calendar.class, "getTimeZone",
- TimeZone.class, null);
- code.invokevirtual().setMethod(type, "setTimeZone", void.class,
- new Class[] { TimeZone.class });
- }
- code.areturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
-
- // new instance factory
- m = bc.declareMethod("newInstance", ProxyCalendar.class, null);
- m.makePublic();
- code = m.getCode(true);
- code.anew().setType(bc);
- code.dup();
- code.invokespecial().setMethod("<init>", void.class, null);
- code.areturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
-
- // proxy the protected computeFields method b/c it is called on
- // mutate, and some setters are final and therefore not proxyable
- m = bc.declareMethod("computeFields", void.class, null);
- m.makeProtected();
- code = m.getCode(true);
- code.aload().setThis();
- code.constant().setValue(true);
- code.invokestatic().setMethod(Proxies.class, "dirty", void.class,
- new Class[] { Proxy.class, boolean.class });
- code.aload().setThis();
- code.invokespecial().setMethod(type, "computeFields", void.class, null);
- code.vreturn();
- code.calculateMaxStack();
- code.calculateMaxLocals();
- }
-
+
/**
* Implement the methods in the {@link ProxyBean} interface.
*/
@@ -2094,13 +2141,17 @@ public class ProxyManagerImpl
}
// ASM generated proxies
- if (Date.class.isAssignableFrom(cls)) {
+ if (Date.class.isAssignableFrom(cls) ||
+ Calendar.class.isAssignableFrom(cls)) {
final String proxyClassName = getProxyClassName(cls, false);
byte[] bytes = null;
if (Date.class.isAssignableFrom(cls)) {
bytes = mgr.generateProxyDateBytecode(cls, false, proxyClassName);
}
+ else if (Calendar.class.isAssignableFrom(cls)) {
+ bytes = mgr.generateProxyCalendarBytecode(cls, false, proxyClassName);
+ }
if (bytes != null) {
final String fileName = cls.getName().replace('.', '$') + PROXY_SUFFIX + ".class";
java.nio.file.Files.write(new File(dir, fileName).toPath(), bytes);
@@ -2112,8 +2163,6 @@ public class ProxyManagerImpl
bc = mgr.generateProxyCollectionBytecode(cls, false);
else if (Map.class.isAssignableFrom(cls))
bc = mgr.generateProxyMapBytecode(cls, false);
- else if (Calendar.class.isAssignableFrom(cls))
- bc = mgr.generateProxyCalendarBytecode(cls, false);
else {
final Class fCls = cls;
// TODO Move this to J2DOPrivHelper