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
The following commit(s) were added to refs/heads/master by this push: new 6eeb025cf OPENJPA-2911 migrate InterfaceImplGenerator wip 6eeb025cf is described below commit 6eeb025cf3e771da8461633813e1926d912d2aab Author: Mark Struberg <strub...@apache.org> AuthorDate: Wed Jul 19 17:25:52 2023 +0200 OPENJPA-2911 migrate InterfaceImplGenerator wip Still not really there. There is still some very weirdo ClassLoader mixup which gets 'fixed' as sideeffect of using a roundtrip to BCClass. Not yet 100% sure yet, still digging --- .../org/apache/openjpa/enhance/PCEnhancer.java | 58 ++--- .../apache/openjpa/enhance/SerpPrivacyHelper.java | 37 --- .../openjpa/meta/InterfaceImplGenerator.java | 122 +++++----- .../org/apache/openjpa/util/asm/AsmHelper.java | 63 +++--- .../openjpa/util/asm/EnhancementClassLoader.java | 10 - .../openjpa/util/asm/EnhancementProject.java | 2 - .../openjpa/enhance/TestSubclassValidator.java | 9 +- .../openjpa/persistence/test/ClassSelector.java | 247 --------------------- 8 files changed, 115 insertions(+), 433 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 bf852f34a..c3ebe76f8 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 @@ -849,7 +849,7 @@ public class PCEnhancer { // default: throw new IllegalArgumentException () instructions.add(defLbl); - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } else { // In mixed access mode, property indexes are not +1 incremental @@ -1401,7 +1401,7 @@ public class PCEnhancer { final InsnList instructions = newInstance.instructions; if ((pc.getClassNode().access & Opcodes.ACC_ABSTRACT) > 0) { - instructions.add(throwException(USEREXCEP)); + instructions.add(AsmHelper.throwException(USEREXCEP)); return; } @@ -1503,7 +1503,7 @@ public class PCEnhancer { FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields() : _meta.getDeclaredFields(); if (fmds.length == 0) { - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } else { // switch (val) @@ -1542,7 +1542,7 @@ public class PCEnhancer { } instructions.add(defaultCase); - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } addMultipleFieldsMethodVersion(classNode, provideFieldsMeth, false); @@ -1565,7 +1565,7 @@ public class PCEnhancer { FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields() : _meta.getDeclaredFields(); if (fmds.length == 0) { - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } else { // switch (val) @@ -1614,7 +1614,7 @@ public class PCEnhancer { } instructions.add(defaultCase); - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } addMultipleFieldsMethodVersion(classNode, replaceFieldMeth, false); @@ -1639,7 +1639,7 @@ public class PCEnhancer { FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields() : _meta.getDeclaredFields(); if (fmds.length == 0) { - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } else { instructions.add(new VarInsnNode(Opcodes.ILOAD, relLocal)); @@ -1666,7 +1666,7 @@ public class PCEnhancer { } instructions.add(defaultCase); - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } addMultipleFieldsMethodVersion(classNode, copyFieldMeth, true); @@ -1719,7 +1719,7 @@ public class PCEnhancer { instructions.add(new InsnNode(Opcodes.RETURN)); } else { - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); } instructions.add(afterRelCheck); @@ -1798,7 +1798,7 @@ public class PCEnhancer { instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE))); LabelNode toEndSmCmp = new LabelNode(); instructions.add(new JumpInsnNode(Opcodes.IF_ACMPEQ, toEndSmCmp)); - instructions.add(throwException(IllegalArgumentException.class)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class)); instructions.add(toEndSmCmp); // if (pcStateManager == null) @@ -1807,7 +1807,7 @@ public class PCEnhancer { instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, SM, Type.getDescriptor(SMTYPE))); LabelNode toEndSmNull = new LabelNode(); instructions.add(new JumpInsnNode(Opcodes.IFNONNULL, toEndSmNull)); - instructions.add(throwException(IllegalStateException.class)); + instructions.add(AsmHelper.throwException(IllegalStateException.class)); instructions.add(toEndSmNull); } @@ -2179,7 +2179,7 @@ public class PCEnhancer { // single field identity always throws exception if (_meta.isOpenJPAIdentity()) { - instructions.add(throwException(INTERNEXCEP)); + instructions.add(AsmHelper.throwException(INTERNEXCEP)); return; } @@ -3078,7 +3078,7 @@ public class PCEnhancer { // throw new IllegalArgumentException (...); String msg = _loc.get("str-cons", oidType, _meta.getDescribedType()).getMessage(); - instructions.add(throwException(IllegalArgumentException.class, msg)); + instructions.add(AsmHelper.throwException(IllegalArgumentException.class, msg)); return; } @@ -3247,38 +3247,6 @@ public class PCEnhancer { } } - - /** - * Helper method to add the code necessary to throw the given - * exception type, sans message. - */ - private InsnList throwException(Class type) { - return throwException(type, null); - } - - /** - * Helper method to add the code necessary to throw the given - * exception type, sans message. - */ - private InsnList throwException(Class type, String msg) { - InsnList instructions = new InsnList(); - instructions.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(type))); - instructions.add(new InsnNode(Opcodes.DUP)); - if (msg != null) { - instructions.add(AsmHelper.getLoadConstantInsn(msg)); - } - String desc = msg != null - ? Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)) - : Type.getMethodDescriptor(Type.VOID_TYPE); - instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, - Type.getInternalName(type), - "<init>", - desc)); - instructions.add(new InsnNode(Opcodes.ATHROW)); - - return instructions; - } - /** * Adds the PersistenceCapable interface to the class being * enhanced, and adds a default constructor for use by OpenJPA diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/SerpPrivacyHelper.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/SerpPrivacyHelper.java index 7ffdab287..5e984e3cf 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/SerpPrivacyHelper.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/SerpPrivacyHelper.java @@ -20,9 +20,7 @@ import java.security.PrivilegedAction; import org.apache.openjpa.lib.util.J2DoPrivHelper; -import serp.bytecode.BCClass; import serp.bytecode.BCClassLoader; -import serp.bytecode.BCField; import serp.bytecode.Project; /** @@ -59,39 +57,4 @@ public class SerpPrivacyHelper extends J2DoPrivHelper { }; } - /** - * Return a PrivilegeAction object for BCClass.getFields(). - * - * Requires security policy: - * 'permission java.lang.RuntimePermission "getClassLoader";' - * - * @return BCField - */ - public static PrivilegedAction<BCField[]> getBCClassFieldsAction( - final BCClass bcClass, final String fieldName) { - return new PrivilegedAction<BCField []>() { - @Override - public BCField [] run() { - return bcClass.getFields(fieldName); - } - }; - } - - /** - * Return a PrivilegeAction object for Project.loadClass(). - * - * Requires security policy: - * 'permission java.lang.RuntimePermission "createClassLoader";' - * - * @return BCClass - */ - public static PrivilegedAction<BCClass> loadProjectClassAction( - final Project project, final Class<?> clazz) { - return new PrivilegedAction<BCClass>() { - @Override - public BCClass run() { - return project.loadClass(clazz); - } - }; - } } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java index 07fc7ee80..f6410eeb2 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/InterfaceImplGenerator.java @@ -35,13 +35,16 @@ import org.apache.openjpa.util.asm.AsmHelper; import org.apache.openjpa.util.asm.ClassNodeTracker; import org.apache.openjpa.util.asm.EnhancementClassLoader; import org.apache.openjpa.util.asm.EnhancementProject; +import org.apache.xbean.asm9.Opcodes; import org.apache.xbean.asm9.Type; +import org.apache.xbean.asm9.tree.ClassNode; +import org.apache.xbean.asm9.tree.FieldInsnNode; +import org.apache.xbean.asm9.tree.FieldNode; +import org.apache.xbean.asm9.tree.InsnNode; +import org.apache.xbean.asm9.tree.MethodNode; +import org.apache.xbean.asm9.tree.VarInsnNode; import serp.bytecode.BCClass; -import serp.bytecode.BCField; -import serp.bytecode.BCMethod; -import serp.bytecode.Code; -import serp.bytecode.Constants; import serp.bytecode.Project; /** @@ -90,32 +93,30 @@ class InterfaceImplGenerator { ClassMetaData sup = meta.getPCSuperclassMetaData(); if (sup != null) { bc.getClassNode().superName = Type.getInternalName(sup.getInterfaceImpl()); - //X enhLoader = new EnhancementClassLoader(_enhProject, sup.getInterfaceImpl().getClassLoader()); + enhLoader = new EnhancementClassLoader(_enhProject, sup.getInterfaceImpl().getClassLoader()); } FieldMetaData[] fields = meta.getDeclaredFields(); Set<Method> methods = new HashSet<>(); - //X TODO REMOVE - BCClass _bc = new Project().loadClass(getClassName(meta)); - AsmHelper.readIntoBCClass(bc, _bc); - for (FieldMetaData field : fields) { - addField(_bc, iface, field, methods); + addField(bc, iface, field, methods); } - invalidateNonBeanMethods(_bc, iface, methods); + invalidateNonBeanMethods(bc, iface, methods); // first load the base Class<?> as the enhancer requires the class // to be available try { - meta.setInterfaceImpl(Class.forName(_bc.getName(), true, loader)); + meta.setInterfaceImpl(Class.forName(bc.getClassNode().name.replace("/", "."), true, loader)); } catch (Throwable t) { - throw new InternalException(_loc.get("interface-load", iface, - loader), t).setFatal(true); + throw new InternalException(_loc.get("interface-load", iface, loader), t).setFatal(true); } // copy the BCClass<?> into the enhancer project. //X bc = _enhProject.loadClass(new ByteArrayInputStream(_bc.toByteArray()), loader); + //X TODO REMOVE + BCClass _bc = new Project().loadClass(getClassName(meta)); + AsmHelper.readIntoBCClass(bc, _bc); ClassNodeTracker bcEnh = AsmHelper.toClassNode(_enhProject, _bc); PCEnhancer enhancer = new PCEnhancer(_repos, bcEnh, meta); @@ -125,8 +126,14 @@ class InterfaceImplGenerator { iface)).setFatal(true); try { // load the Class<?> for real. + EnhancementProject finalProject = new EnhancementProject(); + EnhancementClassLoader finalLoader = new EnhancementClassLoader(finalProject, parentLoader); + final byte[] classBytes2 = AsmHelper.toByteArray(enhancer.getPCBytecode()); + ClassNodeTracker bcEnh2 = finalProject.loadClass(classBytes2, finalLoader); + String pcClassName = enhancer.getPCBytecode().getClassNode().name.replace("/", "."); - impl = Class.forName(pcClassName, true, enhLoader); + impl = Class.forName(pcClassName, true, finalLoader); + } catch (Throwable t) { //X throw new InternalException(_loc.get("interface-load2", iface, enhLoader), t).setFatal(true); throw new InternalException(_loc.get("interface-load2", iface, loader), t).setFatal(true); @@ -140,63 +147,58 @@ class InterfaceImplGenerator { * Add bean getters and setters, also recording seen methods * into the given set. */ - private void addField (BCClass bc, Class<?> iface, FieldMetaData fmd, - Set<Method> methods) { - String name = fmd.getName(); + private void addField (ClassNodeTracker cnt, Class<?> iface, FieldMetaData fmd, Set<Method> methods) { + final ClassNode classNode = cnt.getClassNode(); + String fieldName = fmd.getName(); Class<?> type = fmd.getDeclaredType(); - BCField field = bc.declareField(name, type); - field.setAccessFlags(Constants.ACCESS_PRIVATE); + FieldNode field = new FieldNode(Opcodes.ACC_PRIVATE, fieldName, Type.getDescriptor(type), null, null); + classNode.fields.add(field); // getter - name = StringUtil.capitalize(name); - String prefix = isGetter(iface, fmd) ? "get" : "is"; - BCMethod meth = bc.declareMethod(prefix + name, type, null); - meth.makePublic(); - Code code = meth.getCode(true); - code.aload().setThis(); - code.getfield().setField(field); - code.xreturn().setType(type); - code.calculateMaxStack(); - code.calculateMaxLocals(); - methods.add(getMethodSafe(iface, meth.getName(), null)); + String getterName = (isGetter(iface, fmd) ? "get" : "is") + StringUtil.capitalize(fieldName); + MethodNode meth = new MethodNode(Opcodes.ACC_PUBLIC, + getterName, + Type.getMethodDescriptor(Type.getType(type)), + null, null); + classNode.methods.add(meth); + meth.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this + meth.instructions.add(new FieldInsnNode(Opcodes.GETFIELD, classNode.name, fieldName, Type.getDescriptor(type))); + meth.instructions.add(new InsnNode(AsmHelper.getReturnInsn(type))); + methods.add(getMethodSafe(iface, meth.name, null)); // setter - meth = bc.declareMethod("set" + name, void.class, new Class[]{type}); - meth.makePublic(); - code = meth.getCode(true); - code.aload().setThis(); - code.xload().setParam(0).setType(type); - code.putfield().setField(field); - code.vreturn(); - code.calculateMaxStack(); - code.calculateMaxLocals(); - methods.add(getMethodSafe(iface, meth.getName(), type)); + String setterName = "set" + StringUtil.capitalize(fieldName); + meth = new MethodNode(Opcodes.ACC_PUBLIC, + setterName, + Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(type)), + null, null); + classNode.methods.add(meth); + meth.instructions.add(new VarInsnNode(Opcodes.ALOAD, 0)); // this + meth.instructions.add(new VarInsnNode(AsmHelper.getLoadInsn(type), 1)); // 1st parameter + meth.instructions.add(new FieldInsnNode(Opcodes.PUTFIELD, classNode.name, fieldName, Type.getDescriptor(type))); + meth.instructions.add(new InsnNode(Opcodes.RETURN)); + methods.add(getMethodSafe(iface, meth.name, type)); } /** * Invalidate methods on the interface which are not managed. */ - private void invalidateNonBeanMethods(BCClass bc, Class<?> iface, - Set<Method> methods) { - Method[] meths = (Method[]) AccessController.doPrivileged( - J2DoPrivHelper.getDeclaredMethodsAction(iface)); - BCMethod meth; - Code code; - Class<?> type = _repos.getMetaDataFactory().getDefaults(). - getUnimplementedExceptionType(); + private void invalidateNonBeanMethods(ClassNodeTracker cnt, Class<?> iface, Set<Method> methods) { + Method[] meths = AccessController.doPrivileged(J2DoPrivHelper.getDeclaredMethodsAction(iface)); + + + Class<?> unimplementedExceptionType = _repos.getMetaDataFactory().getDefaults().getUnimplementedExceptionType(); + for (Method method : meths) { - if (methods.contains(method)) + if (methods.contains(method)) { continue; - meth = bc.declareMethod(method.getName(), - method.getReturnType(), method.getParameterTypes()); - meth.makePublic(); - code = meth.getCode(true); - code.anew().setType(type); - code.dup(); - code.invokespecial().setMethod(type, "<init>", void.class, null); - code.athrow(); - code.calculateMaxLocals(); - code.calculateMaxStack(); + } + MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC, + method.getName(), + Type.getMethodDescriptor(method), + null, null); + methodNode.instructions.add(AsmHelper.throwException(unimplementedExceptionType)); + cnt.getClassNode().methods.add(methodNode); } } 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 0e1b007fe..d1ec64140 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 @@ -34,14 +34,16 @@ import org.apache.xbean.asm9.Type; import org.apache.xbean.asm9.tree.AbstractInsnNode; import org.apache.xbean.asm9.tree.ClassNode; import org.apache.xbean.asm9.tree.FieldInsnNode; +import org.apache.xbean.asm9.tree.InsnList; import org.apache.xbean.asm9.tree.InsnNode; import org.apache.xbean.asm9.tree.IntInsnNode; import org.apache.xbean.asm9.tree.LdcInsnNode; +import org.apache.xbean.asm9.tree.MethodInsnNode; import org.apache.xbean.asm9.tree.MethodNode; +import org.apache.xbean.asm9.tree.TypeInsnNode; import org.apache.xbean.asm9.tree.VarInsnNode; import serp.bytecode.BCClass; -import serp.bytecode.Project; /** * Utility methods to deal with ASM bytecode @@ -100,21 +102,6 @@ public final class AsmHelper { return classNode; } - /** - * temporary helper class to convert BCClass to ASM ClassWriter - * @deprecated must get removed when done with migrating from Serp to ASM - */ - public static ClassWriterTracker toClassWriter(BCClass bcClass) { - ClassReader cr = new ClassReader(bcClass.toByteArray()); - ClassWriter cw = new BCClassWriter(ClassWriter.COMPUTE_FRAMES, bcClass.getClassLoader()); - cr.accept(cw, ATTRS, 0); // 0 -> don't skip anything - ClassWriterTracker cwt = new ClassWriterTracker(cw, bcClass.getClassLoader()); - cwt.setName(bcClass.getName()); - - return cwt; - } - - public static byte[] getClassBytes(final String typeName) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(1024); @@ -149,17 +136,6 @@ public final class AsmHelper { return cw.toByteArray(); } - /** - * temporary helper class to convert ClassWriterTracker to BCClass - * @deprecated must get removed when done with migrating from Serp to ASM - */ - public static BCClass toBCClass(ClassWriterTracker cwt) { - final byte[] classBytes = cwt.getCw().toByteArray(); - BCClass bcClass = new Project().loadClass(new ByteArrayInputStream(classBytes), cwt.getClassLoader()); - bcClass.setName(cwt.getName()); - return bcClass; - } - /** * temporary helper class to convert BCClass to ASM ClassNode * @deprecated must get removed when done with migrating from Serp to ASM @@ -689,6 +665,39 @@ public final class AsmHelper { } } + + /** + * Helper method to add the code necessary to throw the given + * exception type, sans message. + */ + public static InsnList throwException(Class type) { + return throwException(type, null); + } + + /** + * Helper method to add the code necessary to throw the given + * exception type, sans message. + */ + public static InsnList throwException(Class type, String msg) { + InsnList instructions = new InsnList(); + instructions.add(new TypeInsnNode(Opcodes.NEW, Type.getInternalName(type))); + instructions.add(new InsnNode(Opcodes.DUP)); + if (msg != null) { + instructions.add(AsmHelper.getLoadConstantInsn(msg)); + } + String desc = msg != null + ? Type.getMethodDescriptor(Type.VOID_TYPE, Type.getType(String.class)) + : Type.getMethodDescriptor(Type.VOID_TYPE); + instructions.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, + Type.getInternalName(type), + "<init>", + desc)); + instructions.add(new InsnNode(Opcodes.ATHROW)); + + return instructions; + } + + public static Class<?> getClass(ClassLoader classLoader, String internalTypeName) { try { return Class.forName(internalTypeName.replace("/", "."), false, classLoader); diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementClassLoader.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementClassLoader.java index 462eabc13..c58cecb91 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementClassLoader.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementClassLoader.java @@ -41,16 +41,6 @@ public class EnhancementClassLoader extends ClassLoader { return project; } - @Override - public Class<?> loadClass(String name) throws ClassNotFoundException { - return super.loadClass(name); - } - - @Override - protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { - return super.loadClass(name, resolve); - } - protected Class findClass(String name) throws ClassNotFoundException { byte[] bytes; try { diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementProject.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementProject.java index de93f1a18..0748274c4 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementProject.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/EnhancementProject.java @@ -124,8 +124,6 @@ public class EnhancementProject { ClassNode classNode = new ClassNode(); cr.accept(classNode, AsmHelper.ATTRS, 0); ClassNodeTracker cnt = new ClassNodeTracker(this, classNode, loader); - String name = classNode.name.replace("/", "."); - classNodeTrackers.put(name, cnt); return cnt; } diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java index 0e774c015..52890cc63 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestSubclassValidator.java @@ -26,6 +26,7 @@ import org.apache.openjpa.persistence.common.apps.Department; import org.apache.openjpa.persistence.common.apps.RuntimeTest2; import org.apache.openjpa.persistence.test.SingleEMFTestCase; import org.apache.openjpa.util.asm.AsmHelper; +import org.apache.openjpa.util.asm.EnhancementProject; import org.apache.xbean.asm9.tree.ClassNode; import org.junit.Test; @@ -34,8 +35,6 @@ import jakarta.persistence.AccessType; import jakarta.persistence.Basic; import jakarta.persistence.Entity; import jakarta.persistence.Id; -import serp.bytecode.BCClass; -import serp.bytecode.Project; public class TestSubclassValidator extends SingleEMFTestCase { @Override @@ -50,7 +49,7 @@ public class TestSubclassValidator extends SingleEMFTestCase { @Test public void testBcSubclassValidator() throws Exception { - Project project = new Project(); + EnhancementProject project = new EnhancementProject(); TemporaryClassLoader tempCl = new TemporaryClassLoader(this.getClass().getClassLoader()); final OpenJPAConfiguration conf = emf.getConfiguration(); @@ -61,7 +60,7 @@ public class TestSubclassValidator extends SingleEMFTestCase { { ClassNode classNode = AsmHelper.readClassNode(EnhanceableGetterEntity.class.getClassLoader(), EnhanceableGetterEntity.class.getName()); - final BCClass bcClass = project.loadClass(EnhanceableGetterEntity.class.getName(), tempCl); + project.loadClass(EnhanceableGetterEntity.class.getName(), tempCl); final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(EnhanceableGetterEntity.class.getName()), tempCl, false); PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, classNode, log, true); subclassValidator.assertCanSubclass(); @@ -69,7 +68,7 @@ public class TestSubclassValidator extends SingleEMFTestCase { { ClassNode classNode = AsmHelper.readClassNode(UnenhancedPropertyAccess.class.getClassLoader(), UnenhancedPropertyAccess.class.getName()); - final BCClass bcClass = project.loadClass(UnenhancedPropertyAccess.class.getName(), tempCl); + project.loadClass(UnenhancedPropertyAccess.class.getName(), tempCl); final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(UnenhancedPropertyAccess.class.getName()), tempCl, false); PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, classNode, log, true); subclassValidator.assertCanSubclass(); diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/ClassSelector.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/ClassSelector.java deleted file mode 100644 index e5c755196..000000000 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/ClassSelector.java +++ /dev/null @@ -1,247 +0,0 @@ -/** - * 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.openjpa.persistence.test; - -import java.io.File; -import java.io.FilenameFilter; -import java.util.ArrayList; -import java.util.List; - -import serp.bytecode.Annotations; -import serp.bytecode.BCClass; -import serp.bytecode.BCMethod; -import serp.bytecode.Project; - -/** - * List class names that match specific selection criteria based on inheritance, - * implemented interface or annotations. The classes are scanned starting from - * a root directory or a single file. Uses serp bytecode library for reading the - * bytecode. The classes are not loaded in Java Virtual Machine and hence - * dependent classes need not be in the classpath. - * - * @author Pinaki Poddar - * - */ -public class ClassSelector { - private List<String> _supers = new ArrayList<>(); - private List<String> _interfaces = new ArrayList<>(); - private List<String> _annotations = new ArrayList<>(); - - /** - * Prints the class names that satisfy the following criteria - * extends org.apache.openjpa.persistence.test.SingleEMFTestCase or - * junit.framework.TestCase - * and annotated with org.apache.openjpa.persistence.test.AllowFailure - * - * @param args the root directory of the class files to be scanned. If no - * argument is given then assumes the current directory. - * - */ - public static void main(String[] args) throws Exception { - String dir = (args.length == 0) ? System.getProperty("user.dir") - : args[0]; - ClassSelector reader = new ClassSelector() - .addSuper("org.apache.openjpa.persistence.test.SingleEMTestCase") - .addSuper("org.apache.openjpa.persistence.test.SingleEMFTestCase") - .addSuper("org.apache.openjpa.persistence.kernel.BaseKernelTest") - .addSuper("org.apache.openjpa.persistence.query.BaseQueryTest") - .addSuper("org.apache.openjpa.persistence.jdbc.kernel.BaseJDBCTest") - .addSuper( - "org.apache.openjpa.persistence.common.utils.AbstractTestCase") - .addAnnotation("org.apache.openjpa.persistence.test.AllowFailure"); - List<String> names = reader.list(new File(dir), true); - String spec = reader.getSpecification(); - System.err.println("Found " + names.size() + " classes under " - + dir + (spec.length() > 0 ? " that" : "")); - System.err.println(spec); - for (String name : names) - System.err.println(name); - } - - /** - * List all the class names that match the selection. - * - * @param file a root file or directory - * @param recursive if true scans all directory recursively - * @return list of class names that match the selection. - */ - public List<String> list(File file, boolean recursive) { - List<String> names = new ArrayList<>(); - list(file, recursive, names); - return names; - } - - private void list(File file, boolean recursive, List<String> names) { - if (file.isDirectory()) { - if (recursive) { - String[] children = file.list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return name.endsWith(".class"); - } - }); - for (String name : children) - list(new File(file, name), recursive, names); - String[] dirs = file.list(new FilenameFilter() { - @Override - public boolean accept(File dir, String name) { - return new File(dir, name).isDirectory(); - } - }); - for (String name : dirs) - list(new File(file, name), recursive, names); - } - } else if (file.getName().endsWith(".class")) { - String cls = select(file); - if (cls != null) - names.add(cls); - } - } - - /** - * Adds fully-qualified name of a super class for selection. - */ - public ClassSelector addSuper(String s) { - _supers.add(s); - return this; - } - - /** - * Adds fully-qualified name of an interface for selection. - */ - public ClassSelector addInterface(String s) { - _interfaces.add(s); - return this; - } - - /** - * Adds fully-qualified name of an annotation for selection. - */ - public ClassSelector addAnnotation(String s) { - _annotations.add(s); - return this; - } - - private String select(File file) { - try { - BCClass bcls = new Project().loadClass(file); - if (applyInheritanceFilter(bcls) - && applyInterfaceFilter(bcls) - && applyAnnotationFilter(bcls)) - return bcls.getName(); - } catch (Exception e) { - System.err.println("Error reading " + file.getAbsolutePath() - + " : " + e); - } - return null; - } - - /** - * Affirms if super class of the given class matches any of the - * selection filter names. If no super class name has been set for - * selection then return true. - * - * @see #addSuper(String) - */ - private boolean applyInheritanceFilter(BCClass bcls) { - if (_supers.isEmpty()) - return true; - String superc = bcls.getSuperclassName(); - return _supers.contains(superc); - } - - /** - * Affirms if interfaces of the given class match any of the - * selection filter names. If no interface name has been set for - * selection then return true. - * - * @see #addInterface(String) - */ - private boolean applyInterfaceFilter(BCClass bcls) { - if (_interfaces.isEmpty()) - return true; - String[] ifaces = bcls.getInterfaceNames(); - if (ifaces == null || ifaces.length == 0) - return false; - for (String iface : ifaces) - if (_interfaces.contains(iface)) - return true; - return false; - } - - /** - * Affirms if annotations of the given class or its methods match any of the - * selection filter names. If no annotation name has been set for - * selection then return true. - * - * @see #addAnnotation(String) - */ - private boolean applyAnnotationFilter(BCClass bcls) { - if (_annotations.isEmpty()) - return true; - Annotations annos = bcls.getDeclaredRuntimeAnnotations(false); - if (hasAnnotation(annos)) - return true; - BCMethod[] methods = bcls.getDeclaredMethods(); - for (BCMethod m : methods) { - annos = m.getDeclaredRuntimeAnnotations(false); - if (hasAnnotation(annos)) - return true; - } - return false; - } - - private boolean hasAnnotation(Annotations annos) { - if (annos == null) - return false; - for (String anno : _annotations) - if (annos.getAnnotation(anno) != null) - return true; - return false; - } - - /** - * Gets a printable description of the currently set selection criteria. - */ - public String getSpecification() { - StringBuilder tmp = new StringBuilder(); - String and = ""; - if (!_supers.isEmpty()) { - tmp.append("\textends "); - and = "and "; - for (int i=0; i<_supers.size(); i++) - tmp.append(_supers.get(i)).append( - (i != _supers.size()-1 ? "\r\n\t or " : "\r\n")); - } - if (!_interfaces.isEmpty()) { - tmp.append("\t" + and + "implements "); - and = "and "; - for (int i=0; i<_interfaces.size(); i++) - tmp.append(_interfaces.get(i)).append( - (i != _interfaces.size()-1 ? "\r\n\t or " : "\r\n")); - } - if (!_annotations.isEmpty()) { - tmp.append("\t" + and + "annotatated with "); - for (int i=0; i<_annotations.size(); i++) - tmp.append(_annotations.get(i)) - .append((i != _annotations.size()-1 ? " or " : "\r\n")); - } - return tmp.toString(); - } -}