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/07/16 15:41:05 UTC
[openjpa] branch master updated (0ab02d696 -> 96a64bceb)
This is an automated email from the ASF dual-hosted git repository.
struberg pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/openjpa.git
from 0ab02d696 OPENJPA-2911 AuxilaryEnhancer in ASM
new a25ad4fc9 OPENJPA-2911 getIdClassConstructorParmOrder in ASM
new 96a64bceb OPENJPA-2911 simplification and more modern code
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../org/apache/openjpa/enhance/PCEnhancer.java | 305 +++++++--------------
.../org/apache/openjpa/util/asm/AsmHelper.java | 75 +++--
.../org/apache/openjpa/enhance/TestAsmAdaptor.java | 33 +--
3 files changed, 162 insertions(+), 251 deletions(-)
[openjpa] 02/02: OPENJPA-2911 simplification and more modern code
Posted by st...@apache.org.
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 96a64bcebaf921c7f25053040ba9a18e1cac62a9
Author: Mark Struberg <st...@apache.org>
AuthorDate: Sun Jul 16 17:40:45 2023 +0200
OPENJPA-2911 simplification and more modern code
---
.../org/apache/openjpa/enhance/PCEnhancer.java | 151 ++++++---------------
.../org/apache/openjpa/util/asm/AsmHelper.java | 26 ++--
.../org/apache/openjpa/enhance/TestAsmAdaptor.java | 24 +---
3 files changed, 61 insertions(+), 140 deletions(-)
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
index dee730d1c..53a0b5f08 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
@@ -31,7 +31,6 @@ import java.io.ObjectStreamClass;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.Serializable;
-import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -107,17 +106,7 @@ import org.apache.xbean.asm9.Type;
import org.apache.xbean.asm9.tree.*;
import serp.bytecode.BCClass;
-import serp.bytecode.BCField;
-import serp.bytecode.BCMethod;
-import serp.bytecode.Code;
-import serp.bytecode.Constants;
-import serp.bytecode.Exceptions;
-import serp.bytecode.IfInstruction;
-import serp.bytecode.Instruction;
-import serp.bytecode.JumpInstruction;
-import serp.bytecode.LoadInstruction;
import serp.bytecode.Project;
-import serp.bytecode.PutFieldInstruction;
/**
* Bytecode enhancer used to enhance persistent classes from metadata. The
@@ -146,17 +135,17 @@ public class PCEnhancer {
public static final String ISDETACHEDSTATEDEFINITIVE = PRE
+ "isDetachedStateDefinitive";
- private static final Class PCTYPE = PersistenceCapable.class;
+ private static final Class<?> PCTYPE = PersistenceCapable.class;
private static final String SM = PRE + "StateManager";
- private static final Class SMTYPE = StateManager.class;
+ private static final Class<?> SMTYPE = StateManager.class;
private static final String INHERIT = PRE + "InheritedFieldCount";
private static final String CONTEXTNAME = "GenericContext";
- private static final Class USEREXCEP = UserException.class;
- private static final Class INTERNEXCEP = InternalException.class;
- private static final Class HELPERTYPE = PCRegistry.class;
+ private static final Class<?> USEREXCEP = UserException.class;
+ private static final Class<?> INTERNEXCEP = InternalException.class;
+ private static final Class<?> HELPERTYPE = PCRegistry.class;
private static final String SUPER = PRE + "PCSuperclass";
private static final Class OIDFSTYPE = FieldSupplier.class;
- private static final Class OIDFCTYPE = FieldConsumer.class;
+ private static final Class<?> OIDFCTYPE = FieldConsumer.class;
private static final String VERSION_INIT_STR = PRE + "VersionInit";
@@ -183,19 +172,16 @@ public class PCEnhancer {
}
}
_auxEnhancers = (AuxiliaryEnhancer[]) auxEnhancers.toArray
- (new AuxiliaryEnhancer[auxEnhancers.size()]);
+ (new AuxiliaryEnhancer[0]);
int rev = 0;
Properties revisionProps = new Properties();
try {
InputStream in = PCEnhancer.class.getResourceAsStream("/META-INF/org.apache.openjpa.revision.properties");
if (in != null) {
- try {
+ try (in) {
revisionProps.load(in);
}
- finally {
- in.close();
- }
}
rev = GitUtils.convertGitInfoToPCEnhancerVersion(revisionProps.getProperty("openjpa.enhancer.revision"));
}
@@ -251,7 +237,7 @@ public class PCEnhancer {
* up the metadata for <code>type</code> from <code>conf</code>'s
* repository.
*/
- public PCEnhancer(OpenJPAConfiguration conf, Class type) {
+ public PCEnhancer(OpenJPAConfiguration conf, Class<?> type) {
this(conf, AccessController.doPrivileged(J2DoPrivHelper
.loadProjectClassAction(new Project(), type)),
(MetaDataRepository) null);
@@ -1004,42 +990,6 @@ public class PCEnhancer {
}
}
- /**
- * get the Method with the given methodName and params from the given classNode or clazz
- * @param classNodeTracker
- * @param methodName
- */
- private static MethodNode getMethod(ClassNodeTracker classNodeTracker, String methodName, Class<?> returnType, Class<?>... paramTypes) {
- Type[] parms = Arrays.stream(paramTypes)
- .map(c -> Type.getType(c))
- .toArray(Type[]::new);
-
- String methodDescription = Type.getMethodDescriptor(Type.getType(returnType), parms);
-
- final Optional<MethodNode> methodNode = classNodeTracker.getClassNode().methods.stream()
- .filter(mn -> mn.name.equals(methodName) && mn.desc.equals(methodDescription))
- .findAny();
- if (methodNode.isPresent()) {
- return methodNode.get();
- }
-
- // otherwise look up the parent class hierarchy
- final String superName = classNodeTracker.getClassNode().superName;
- if (superName == null || superName.equals("java/lang/Object")) {
- // no need to dig further
- return null;
- }
- try {
- final Class<?> parentClass = classNodeTracker.getClassLoader().loadClass(superName.replace("/", "."));
- Method m = getMethod(parentClass, methodName, paramTypes);
- return new MethodNode(m.getModifiers(), m.getName(), Type.getMethodDescriptor(m), null, null);
- }
- catch (ClassNotFoundException e) {
- throw new RuntimeException("Illegal superclass in ClassNode " + classNodeTracker.getClassNode().name, e);
- }
-
- }
-
private static Method getMethod(Class<?> clazz, String methodName, Class<?>... paramTypes) {
try {
return clazz.getDeclaredMethod(methodName, paramTypes);
@@ -1948,7 +1898,7 @@ public class PCEnhancer {
String name = PRE + StringUtil.capitalize(m.getName());
Class[] params = m.getParameterTypes();
Type[] paramTypes = Arrays.stream(params)
- .map(p -> Type.getType(p))
+ .map(Type::getType)
.toArray(Type[]::new);
Class returnType = m.getReturnType();
@@ -2281,7 +2231,7 @@ public class PCEnhancer {
if (pkfields != null) {
// search for a constructor on the IdClass that can be used
// to construct the IdClass
- int parmOrder[] = getIdClassConstructorParmOrder(oidType, pkfields, fmds);
+ int[] parmOrder = getIdClassConstructorParmOrder(oidType, pkfields, fmds);
if (parmOrder != null) {
// If using a field manager, values must be loaded into locals so they can be properly ordered
// as constructor parameters.
@@ -2344,7 +2294,7 @@ public class PCEnhancer {
// invoke the public constructor to create a new local id
Type[] parms = Arrays.stream(clsArgs)
- .map(c -> Type.getType(c))
+ .map(Type::getType)
.toArray(Type[]::new);
instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL,
@@ -3268,7 +3218,7 @@ public class PCEnhancer {
// use reflection to return the right method
String name = prefix + typeName + "Field";
- Class[] params = (Class[]) plist.toArray(new Class[plist.size()]);
+ Class[] params = (Class[]) plist.toArray(new Class[0]);
try {
return AccessController.doPrivileged(
@@ -4166,15 +4116,10 @@ public class PCEnhancer {
}
}
- // create template super.clone () instruction to match against
- Instruction template = (AccessController.doPrivileged(
- J2DoPrivHelper.newCodeAction())).invokespecial()
- .setMethod(superName, "clone", Object.class.getName(), null);
-
// find calls to the template instruction; on match
// clone will be on stack
AbstractInsnNode insn = cloneMeth.instructions.getFirst();
- while ((insn = searchNextInstruction(insn, i -> i.getOpcode() == Opcodes.INVOKESPECIAL &&
+ if ((insn = searchNextInstruction(insn, i -> i.getOpcode() == Opcodes.INVOKESPECIAL &&
i instanceof MethodInsnNode && ((MethodInsnNode) i).name.equals("clone"))
) != null) {
// ((<type>) clone).pcStateManager = null;
@@ -4185,7 +4130,6 @@ public class PCEnhancer {
instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
cloneMeth.instructions.insert(insn, instructions);
- break;
}
}
@@ -4336,7 +4280,6 @@ public class PCEnhancer {
null, null);
classNode.methods.add(getterMethod);
final InsnList instructions = getterMethod.instructions;
- int nextFreeVarPos = 2;
// if we're not already tracking field access via reflection, then we
// must make the getter hook in lazy loading before accessing the super
@@ -4377,11 +4320,11 @@ public class PCEnhancer {
}
// if (inst.pcStateManager == null) return inst.<field>;
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
LabelNode afterIfNonNull = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, afterIfNonNull));
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
addGetManagedValueCode(classNode, instructions, fmd, true);
instructions.add(new InsnNode(AsmHelper.getReturnInsn(fmd.getDeclaredType())));
@@ -4395,7 +4338,7 @@ public class PCEnhancer {
// inst.pcStateManager.accessingField (field);
// return inst.<field>;
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
instructions.add(new VarInsnNode(Opcodes.ILOAD, fieldLocalVarPos));
instructions.add(new MethodInsnNode(Opcodes.INVOKEINTERFACE,
@@ -4403,7 +4346,7 @@ public class PCEnhancer {
"accessingField",
Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE)));
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
addGetManagedValueCode(classNode, instructions, fmd, true);
instructions.add(new InsnNode(AsmHelper.getReturnInsn(fmd.getDeclaredType())));
}
@@ -4427,12 +4370,12 @@ public class PCEnhancer {
int fieldParamPos = 1;
// if (inst.pcStateManager == null) inst.<field> = value;
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
LabelNode lblAfterIfNonNull = new LabelNode();
instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, lblAfterIfNonNull));
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
instructions.add(new VarInsnNode(AsmHelper.getLoadInsn(fmd.getDeclaredType()), fieldParamPos));
addSetManagedValueCode(classNode, instructions, fmd);
if (fmd.isVersion() && _addVersionInitFlag) {
@@ -4450,15 +4393,15 @@ public class PCEnhancer {
// inst.pcStateManager.setting<fieldType>Field (inst,
// pcInheritedFieldCount + <index>, inst.<field>, value, 0);
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE)));
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
instructions.add(new FieldInsnNode(Opcodes.GETSTATIC, classNode.name, INHERIT, Type.INT_TYPE.getDescriptor()));
instructions.add(AsmHelper.getLoadConstantInsn(index));
instructions.add(new InsnNode(Opcodes.IADD));
- instructions.add(loadManagedInstance(true, fmd));
+ instructions.add(loadManagedInstance());
addGetManagedValueCode(classNode, instructions, fmd, true);
instructions.add(new VarInsnNode(AsmHelper.getLoadInsn(fmd.getDeclaredType()), fieldParamPos));
instructions.add(new InsnNode(Opcodes.ICONST_0));
@@ -4770,7 +4713,7 @@ public class PCEnhancer {
final List<FieldNode> fields = managedType.getClassNode().fields;
List<FieldNode> unmgd = new ArrayList(fields.size());
for (FieldNode field : fields) {
- if ((field.access & (Opcodes.ACC_TRANSIENT) | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL) == 0
+ if ((field.access & (Opcodes.ACC_TRANSIENT | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL)) == 0
&& !field.name.startsWith(PRE)
&& _meta.getDeclaredField(field.name) == null) {
unmgd.add(field);
@@ -5336,18 +5279,13 @@ public class PCEnhancer {
* <code>code</code> is in an accessor method or another static method;
* otherwise, it is in one of the PC-specified methods.
*
- * @return the first instruction added to <code>code</code>.
+ * @return instruction to load the persistence context to the stack.
*/
- private AbstractInsnNode loadManagedInstance(boolean forStatic, FieldMetaData fmd) {
- if (forStatic && isFieldAccess(fmd)) {
- // 1st method parameter is position 0 on the stack for a STATIC method!
- return new VarInsnNode(Opcodes.ALOAD, 0);
- }
- return new VarInsnNode(Opcodes.ALOAD, 0); // this
- }
-
- private int getAccessorParameterOffset(FieldMetaData fmd) {
- return isFieldAccess(fmd) ? 1 : 0;
+ private AbstractInsnNode loadManagedInstance() {
+ // 1st method parameter is position 0 on the stack for a STATIC method
+ // or use the this* for a non-STATIC method
+ // In both cases we end up with ALOAD_0, while it essentially does different things.
+ return new VarInsnNode(Opcodes.ALOAD, 0);
}
/**
@@ -5373,7 +5311,7 @@ public class PCEnhancer {
}
/**
- * Create the generated getter {@link BCMethod} for <code>fmd</code>. The
+ * Create the generated getter {@link MethodNode} for <code>fmd</code>. The
* calling environment will then populate this method's code block.
*/
private MethodNode createGetMethod(ClassNode classNode, FieldMetaData fmd) {
@@ -5384,7 +5322,7 @@ public class PCEnhancer {
.findFirst()
.get();
- MethodNode getter = new MethodNode((field.access & ~Constants.ACCESS_TRANSIENT & ~Constants.ACCESS_VOLATILE)
+ MethodNode getter = new MethodNode((field.access & ~Opcodes.ACC_TRANSIENT & ~Opcodes.ACC_VOLATILE)
| Opcodes.ACC_FINAL | Opcodes.ACC_STATIC,
PRE + "Get" + fmd.getName(),
Type.getMethodDescriptor(Type.getType(fmd.getDeclaredType()), Type.getObjectType(classNode.name)),
@@ -5431,7 +5369,7 @@ public class PCEnhancer {
}
/**
- * Create the generated setter {@link BCMethod} for <code>fmd</code>. The
+ * Create the generated setter {@link MethodNode} for <code>fmd</code>. The
* calling environment will then populate this method's code block.
*/
private MethodNode createSetMethod(ClassNode classNode, FieldMetaData fmd) {
@@ -5441,7 +5379,7 @@ public class PCEnhancer {
.filter(f -> f.name.equals(fmd.getName()))
.findFirst()
.get();
- MethodNode setter = new MethodNode((field.access & ~Constants.ACCESS_TRANSIENT & ~Constants.ACCESS_VOLATILE)
+ MethodNode setter = new MethodNode((field.access & ~Opcodes.ACC_TRANSIENT & ~Opcodes.ACC_VOLATILE)
| Opcodes.ACC_FINAL | Opcodes.ACC_STATIC,
PRE + "Set" + fmd.getName(),
Type.getMethodDescriptor(Type.VOID_TYPE,
@@ -5550,17 +5488,14 @@ public class PCEnhancer {
*/
public static boolean run(final String[] args, Options opts) {
return Configurations.runAgainstAllAnchors(opts,
- new Configurations.Runnable() {
- @Override
- public boolean run(Options opts) throws IOException {
- OpenJPAConfiguration conf = new OpenJPAConfigurationImpl();
- try {
- return PCEnhancer.run(conf, args, opts);
- } finally {
- conf.close();
- }
- }
- });
+ opts1 -> {
+ OpenJPAConfiguration conf = new OpenJPAConfigurationImpl();
+ try {
+ return run(conf, args, opts1);
+ } finally {
+ conf.close();
+ }
+ });
}
/**
@@ -5792,7 +5727,7 @@ public class PCEnhancer {
return null;
}
- int parmOrder[] = new int[pkfields.size()];
+ int[] parmOrder = new int[pkfields.size()];
for (MethodNode ct : cts) {
if ((ct.access & Opcodes.ACC_PUBLIC) == 0) {
// ignore non public constructors
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
index a5e55ca34..6bb378e3f 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
@@ -172,7 +172,7 @@ public final class AsmHelper {
public static Optional<MethodNode> getMethodNode(ClassNode classNode, String methodName, Class<?> returnType, Class<?>... paramTypes) {
Type[] parms = Arrays.stream(paramTypes)
- .map(c -> Type.getType(c))
+ .map(Type::getType)
.toArray(Type[]::new);
final String mDesc = Type.getMethodDescriptor(Type.getType(returnType), parms);
@@ -187,7 +187,7 @@ public final class AsmHelper {
* @param type the type to get returned
* @return the proper Opcode RETURN, ARETURN, IRETURN, etc
*/
- public static int getReturnInsn(Class type) {
+ public static int getReturnInsn(Class<?> type) {
if (type.equals(Void.TYPE)) {
return Opcodes.RETURN;
}
@@ -225,7 +225,7 @@ public final class AsmHelper {
return new InsnNode(Opcodes.ACONST_NULL);
}
if (val instanceof Integer) {
- final int iVal = ((Integer) val).intValue();
+ final int iVal = (Integer) val;
switch (iVal) {
case 0:
return new InsnNode(Opcodes.ICONST_0);
@@ -253,7 +253,7 @@ public final class AsmHelper {
}
if (val instanceof Boolean) {
- if (((Boolean)val) == true) {
+ if ((Boolean)val) {
return new InsnNode(Opcodes.ICONST_1);
}
else {
@@ -262,31 +262,31 @@ public final class AsmHelper {
}
if (val instanceof Long) {
- if (((Long) val).longValue() == 0L) {
+ if ((Long) val == 0L) {
return new InsnNode(Opcodes.LCONST_0);
}
- if (((Long) val).longValue() == 1L) {
+ if ((Long) val == 1L) {
return new InsnNode(Opcodes.LCONST_1);
}
}
if (val instanceof Float) {
- if (((Float) val).floatValue() == 0F) {
+ if ((Float) val == 0F) {
return new InsnNode(Opcodes.FCONST_0);
}
- if (((Float) val).floatValue() == 1F) {
+ if ((Float) val == 1F) {
return new InsnNode(Opcodes.FCONST_1);
}
- if (((Float) val).floatValue() == 2F) {
+ if ((Float) val == 2F) {
return new InsnNode(Opcodes.FCONST_2);
}
}
if (val instanceof Double) {
- if (((Double) val).doubleValue() == 0D) {
+ if ((Double) val == 0D) {
return new InsnNode(Opcodes.DCONST_0);
}
- if (((Double) val).doubleValue() == 1D) {
+ if ((Double) val == 1D) {
return new InsnNode(Opcodes.DCONST_1);
}
}
@@ -416,7 +416,7 @@ public final class AsmHelper {
* Get the internal names for the given classes
* @see Type#getInternalName(Class)
*/
- public static String[] getInternalNames(Class[] classes) {
+ public static String[] getInternalNames(Class<?>[] classes) {
String[] internalNames = new String[classes.length];
for (int i=0; i<classes.length; i++) {
@@ -430,7 +430,7 @@ public final class AsmHelper {
* get the ASM Types for the given classes
* @see Type#getType(Method)
*/
- public static Type[] getParamTypes(Class[] params) {
+ public static Type[] getParamTypes(Class<?>[] params) {
Type[] types = new Type[params.length];
for (int i=0; i<types.length; i++) {
types[i] = Type.getType(params[i]);
diff --git a/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java b/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java
index 0d928d3ce..ebe8be60b 100644
--- a/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java
+++ b/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java
@@ -50,32 +50,18 @@ public class TestAsmAdaptor
private byte[] bytes(final Class<?> type)
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
- final InputStream stream = Thread.currentThread().getContextClassLoader()
- .getResourceAsStream(type.getName().replace('.', '/') + ".class");
- try
- {
+ try (InputStream stream = Thread.currentThread().getContextClassLoader()
+ .getResourceAsStream(type.getName().replace('.', '/') + ".class")) {
int c;
byte[] buffer = new byte[1024];
- while ((c = stream.read(buffer)) >= 0)
- {
+ while ((c = stream.read(buffer)) >= 0) {
baos.write(buffer, 0, c);
}
}
- catch (IOException e)
- {
+ catch (IOException e) {
fail(e.getMessage());
}
- finally
- {
- try
- {
- stream.close();
- }
- catch (IOException e)
- {
- // no-op
- }
- }
+ // no-op
return baos.toByteArray();
}
[openjpa] 01/02: OPENJPA-2911 getIdClassConstructorParmOrder in ASM
Posted by st...@apache.org.
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 a25ad4fc95bc0d23ba22634a771c330df363017b
Author: Mark Struberg <st...@apache.org>
AuthorDate: Sun Jul 16 17:24:42 2023 +0200
OPENJPA-2911 getIdClassConstructorParmOrder in ASM
---
.../org/apache/openjpa/enhance/PCEnhancer.java | 156 +++++++--------------
.../org/apache/openjpa/util/asm/AsmHelper.java | 49 +++++--
.../org/apache/openjpa/enhance/TestAsmAdaptor.java | 9 ++
3 files changed, 102 insertions(+), 112 deletions(-)
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
index 7ea61e1c0..dee730d1c 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java
@@ -31,6 +31,7 @@ import java.io.ObjectStreamClass;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.Serializable;
+import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
@@ -3592,19 +3593,11 @@ public class PCEnhancer {
Type.LONG_TYPE.getDescriptor(),
null, uid);
pc.getClassNode().fields.add(serVersField);
-
- /* should be done by ASM FieldNode already
- Code code = getOrCreateClassInitCode(false);
- code.beforeFirst();
- code.constant().setValue(uid.longValue());
- code.putstatic().setField(field);
- */
}
}
- MethodNode writeObjectMeth = AsmHelper.getMethodNode(pc.getClassNode(), "writeObject",
- void.class, ObjectOutputStream.class)
- .orElse(null);
+ MethodNode writeObjectMeth = AsmHelper.getMethodNode(pc.getClassNode(), "writeObject",void.class, ObjectOutputStream.class)
+ .orElse(null);
boolean full = writeObjectMeth == null;
@@ -4320,32 +4313,6 @@ public class PCEnhancer {
return false;
}
- private boolean setVisibilityToSuperMethod(BCMethod method) {
- BCMethod[] methods = _managedType.getMethods(method.getName(),
- method.getParamTypes());
- if (methods.length == 0)
- throw new UserException(_loc.get("no-accessor",
- _managedType.getName(), method.getName()));
- BCMethod superMeth = methods[0];
- if (superMeth.isPrivate()) {
- method.makePrivate();
- return true;
- }
- else if (superMeth.isPackage()) {
- method.makePackage();
- return true;
- }
- else if (superMeth.isProtected()) {
- method.makeProtected();
- return true;
- }
- else if (superMeth.isPublic()) {
- method.makePublic();
- return true;
- }
- return false;
- }
-
/**
* Adds a non-static getter that delegates to the super methods, and
* performs any necessary field tracking.
@@ -5363,22 +5330,6 @@ public class PCEnhancer {
}
}
-
- /**
- * Add the {@link Instruction}s to load the instance to modify onto the
- * stack, and return it. If <code>forStatic</code> is set, then
- * <code>code</code> is in an accessor method or another static method;
- * otherwise, it is in one of the PC-specified methods.
- *
- * @return the first instruction added to <code>code</code>.
- */
- @Deprecated
- private Instruction loadManagedInstance(Code code, boolean forStatic, FieldMetaData fmd) {
- if (forStatic && isFieldAccess(fmd))
- return code.aload().setParam(0);
- return code.aload().setThis();
- }
-
/**
* Add the {@link Instruction}s to load the instance to modify onto the
* stack, and return it. If <code>forStatic</code> is set, then
@@ -5395,18 +5346,6 @@ public class PCEnhancer {
return new VarInsnNode(Opcodes.ALOAD, 0); // this
}
- /**
- * Add the {@link Instruction}s to load the instance to modify onto the
- * stack, and return it. This method should not be used to load static
- * fields.
- *
- * @return the first instruction added to <code>code</code>.
- */
- @Deprecated
- private Instruction loadManagedInstance(Code code, boolean forStatic) {
- return loadManagedInstance(code, forStatic, null);
- }
-
private int getAccessorParameterOffset(FieldMetaData fmd) {
return isFieldAccess(fmd) ? 1 : 0;
}
@@ -5840,67 +5779,78 @@ public class PCEnhancer {
* a matching constructor for the provided pk fields. If a match is found, it returns
* the order (relative to the field metadata) of the constructor parameters. If a match
* is not found, returns null.
+ *
+ * We use byte code analysis to find the fields the ct works on.
*/
- private int[] getIdClassConstructorParmOrder(Class<?> oidType, ArrayList<Integer> pkfields,
- FieldMetaData[] fmds) {
- Project project = new Project();
- BCClass bc = project.loadClass(oidType);
- BCMethod[] methods = bc.getDeclaredMethods("<init>");
- if (methods == null || methods.length == 0) {
+ private int[] getIdClassConstructorParmOrder(Class<?> oidType, List<Integer> pkfields, FieldMetaData[] fmds) {
+ final ClassNode classNode = AsmHelper.readClassNode(oidType);
+ final List<MethodNode> cts = classNode.methods.stream()
+ .filter(m -> "<init>".equals(m.name))
+ .collect(Collectors.toList());
+
+ if (cts.isEmpty()) {
return null;
}
int parmOrder[] = new int[pkfields.size()];
- for (BCMethod method : methods) {
- // constructor must be public
- if (!method.isPublic()) {
+ for (MethodNode ct : cts) {
+ if ((ct.access & Opcodes.ACC_PUBLIC) == 0) {
+ // ignore non public constructors
continue;
}
- Class<?>[] parmTypes = method.getParamTypes();
+ Type[] argTypes = Type.getArgumentTypes(ct.desc);
+
// make sure the constructors have the same # of parms as
// the number of pk fields
- if (parmTypes.length != pkfields.size()) {
+ if (listSize(pkfields) != argTypes.length) {
continue;
}
int parmOrderIndex = 0;
- Code code = method.getCode(false);
- Instruction[] ins = code.getInstructions();
- for (int i = 0; i < ins.length; i++) {
- if (ins[i] instanceof PutFieldInstruction) {
- PutFieldInstruction pfi = (PutFieldInstruction)ins[i];
- for (int j = 0; j < pkfields.size(); j++) {
- int fieldNum = pkfields.get(j);
- // Compare the field being set with the current pk field
- String parmName = fmds[fieldNum].getName();
- Class<?> parmType = fmds[fieldNum].getType();
- if (parmName.equals(pfi.getFieldName())) {
- // backup and examine the load instruction parm
- if (i > 0 && ins[i-1] instanceof LoadInstruction) {
- LoadInstruction li = (LoadInstruction)ins[i-1];
- // Get the local index from the instruction. This will be the index
- // of the constructor parameter. must be less than or equal to the
- // max parm index to prevent from picking up locals that could have
- // been produced within the constructor. Also make sure the parm type
- // matches the fmd type
- int parm = li.getLocal();
- if (parm <= pkfields.size() && parmTypes[parm-1].equals(parmType)) {
- parmOrder[parmOrderIndex] = fieldNum;
- parmOrderIndex++;
- }
- } else {
- // Some other instruction found. can't make a determination of which local/parm
- // is being used on the putfield.
- break;
+ AbstractInsnNode insn = ct.instructions.getFirst();
+ // skip to the next PUTFIELD instruction
+ while ((insn = searchNextInstruction(insn, i -> i.getOpcode() == Opcodes.PUTFIELD)) != null) {
+ FieldInsnNode putField = (FieldInsnNode) insn;
+ for (int i = 0; i < pkfields.size(); i++) {
+ int fieldNum = pkfields.get(i);
+ // Compare the field being set with the current pk field
+ String parmName = fmds[fieldNum].getName();
+ Class<?> parmType = fmds[fieldNum].getType();
+ if (parmName.equals(putField.name)) {
+ // backup and examine the load instruction parm
+ if (AsmHelper.isLoadInsn(insn.getPrevious())) {
+ // Get the local index from the instruction. This will be the index
+ // of the constructor parameter. must be less than or equal to the
+ // max parm index to prevent from picking up locals that could have
+ // been produced within the constructor. Also make sure the parm type
+ // matches the fmd type
+
+ VarInsnNode loadInsn = (VarInsnNode) insn.getPrevious();
+
+ int parm = AsmHelper.getParamIndex(ct, loadInsn.var);
+ if (parm < pkfields.size() && argTypes[parm].equals(Type.getType(parmType))) {
+ parmOrder[parmOrderIndex] = fieldNum;
+ parmOrderIndex++;
}
+ } else {
+ // Some other instruction found. can't make a determination of which local/parm
+ // is being used on the putfield.
+ break;
}
}
}
+
+ insn = insn.getNext();
}
if (parmOrderIndex == pkfields.size()) {
return parmOrder;
}
}
+
return null;
}
+
+ private int listSize(Collection<?> coll) {
+ return coll == null ? 0 : coll.size();
+ }
}
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
index 6c7f8c919..a5e55ca34 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/AsmHelper.java
@@ -57,15 +57,22 @@ public final class AsmHelper {
/**
* Read the binary bytecode from the class with the given name
- * @param classBytes the binary of the class
+ * @param clazz the class to read into the ClassNode
* @return the ClassNode constructed from that class
*/
- public static ClassNode readClassNode(byte[] classBytes) {
- ClassReader cr = new ClassReader(classBytes);
- ClassNode classNode = new ClassNode();
- cr.accept(classNode, 0);
-
- return classNode;
+ public static ClassNode readClassNode(Class<?> clazz) {
+ int extPos = clazz.getName().lastIndexOf('.') + 1;
+ String className = clazz.getName().substring(extPos);
+ try (InputStream in = clazz.getResourceAsStream(className + ".class")) {
+ ClassReader cr = new ClassReader(in);
+ ClassNode classNode = new ClassNode();
+ cr.accept(classNode, 0);
+
+ return classNode;
+ }
+ catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
}
/**
@@ -432,6 +439,30 @@ public final class AsmHelper {
return types;
}
+ /**
+ * Determine the 0-based index of the parameter of LOAD or STORE position varPos
+ * @param methodNode
+ * @param varPos the position on the stack
+ * @return the index of the parameter which corresponds to this varPos
+ */
+ public static int getParamIndex(MethodNode methodNode, int varPos) {
+ boolean isStatic = (methodNode.access & Opcodes.ACC_STATIC) > 0;
+ if (!isStatic) {
+ // only static methods start with 0
+ // non-static have the this* on pos 0.
+ varPos--;
+ }
+ final Type[] paramTypes = Type.getArgumentTypes(methodNode.desc);
+ int pos = 0;
+ for (int i=0; i<paramTypes.length; i++) {
+ if (pos==varPos) {
+ return i;
+ }
+ pos += paramTypes[i].getSize();
+ }
+ throw new IllegalArgumentException("Cannot determine parameter position " + varPos + " for method " + methodNode.name);
+ }
+
/**
* @return true if the instruction is an LOAD instruction
*/
@@ -448,10 +479,9 @@ public final class AsmHelper {
|| insn.getOpcode() == Opcodes.BALOAD
|| insn.getOpcode() == Opcodes.CALOAD
|| insn.getOpcode() == Opcodes.SALOAD;
-
-
}
+
/**
* @return true if the instruction is an ALOAD_0
*/
@@ -627,4 +657,5 @@ public final class AsmHelper {
return null;
}
}
+
}
diff --git a/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java b/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java
index 970b98143..0d928d3ce 100644
--- a/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java
+++ b/openjpa-kernel/src/test/java/org/apache/openjpa/enhance/TestAsmAdaptor.java
@@ -19,6 +19,7 @@
package org.apache.openjpa.enhance;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -26,10 +27,18 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import org.apache.openjpa.util.QueryException;
+import org.apache.openjpa.util.asm.AsmHelper;
+import org.apache.xbean.asm9.tree.ClassNode;
import org.junit.Test;
public class TestAsmAdaptor
{
+ @Test
+ public void testAsmHelper() throws Exception {
+ final ClassNode classNode = AsmHelper.readClassNode(QueryException.class);
+ assertNotNull(classNode);
+ }
@Test
public void isEnhanced()
{