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/17 20:33:09 UTC

[openjpa] branch master updated: OPENJPA-2911 openjpa-lib without Serp

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 86c266df7 OPENJPA-2911 openjpa-lib without Serp
86c266df7 is described below

commit 86c266df7a2d2840c0f413ef3ea70741ae1bef3a
Author: Mark Struberg <st...@apache.org>
AuthorDate: Mon Jul 17 22:31:18 2023 +0200

    OPENJPA-2911 openjpa-lib without Serp
---
 .../openjpa/jdbc/meta/ReverseMappingTool.java      |   3 +-
 openjpa-kernel/pom.xml                             |   5 +
 .../openjpa/enhance/DynamicStorageGenerator.java   |   2 +-
 .../org/apache/openjpa/enhance/PCEnhancer.java     |   6 +-
 .../apache/openjpa/enhance/SerpPrivacyHelper.java  |  97 ++++++++++++
 .../openjpa/meta/InterfaceImplGenerator.java       |  11 +-
 .../org/apache/openjpa/util/GeneratedClasses.java  |   3 +-
 openjpa-lib/pom.xml                                |   5 +-
 .../lib/meta/ClassAnnotationMetaDataFilter.java    | 174 ++++-----------------
 .../apache/openjpa/lib/meta/ClassArgParser.java    |  52 ++++--
 .../apache/openjpa/lib/util/J2DoPrivHelper.java    | 128 ---------------
 .../org/apache/openjpa/lib/util/JavaVersions.java  |   7 +-
 .../openjpa/lib/util/TemporaryClassLoader.java     |  48 +++---
 .../apache/openjpa/lib/util/StringUtilTest.java    |   2 -
 .../enhance/TestEnhancementWithMultiplePUs.java    |   6 +-
 15 files changed, 218 insertions(+), 331 deletions(-)

diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java
index 8776d3526..58437e27a 100644
--- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java
+++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java
@@ -45,6 +45,7 @@ import java.util.TreeSet;
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.enhance.ApplicationIdTool;
 import org.apache.openjpa.enhance.CodeGenerator;
+import org.apache.openjpa.enhance.SerpPrivacyHelper;
 import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
 import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
 import org.apache.openjpa.jdbc.meta.strats.FullClassStrategy;
@@ -183,7 +184,7 @@ public class ReverseMappingTool
     private final Map _tables = new HashMap();
     private final Project _project = new Project();
     private final BCClassLoader _loader = AccessController
-        .doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(_project));
+        .doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(_project));
     private StrategyInstaller _strat = null;
     private String _package = null;
     private File _dir = null;
diff --git a/openjpa-kernel/pom.xml b/openjpa-kernel/pom.xml
index b1eb29b08..01b139724 100644
--- a/openjpa-kernel/pom.xml
+++ b/openjpa-kernel/pom.xml
@@ -66,6 +66,11 @@
             <version>4.2.0</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <!-- TODO REMOVE -->
+            <groupId>net.sourceforge.serp</groupId>
+            <artifactId>serp</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.apache.xbean</groupId>
             <artifactId>xbean-asm9-shaded</artifactId>
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
index 9bc1fd000..e1b2b85b1 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/DynamicStorageGenerator.java
@@ -97,7 +97,7 @@ public class DynamicStorageGenerator {
     // the project/classloader for the classes.
     private final Project _project = new Project();
     private final BCClassLoader _loader =
-        AccessController.doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(
+        AccessController.doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(
             _project, AccessController.doPrivileged(J2DoPrivHelper
                 .getClassLoaderAction(DynamicStorage.class))));
 
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 8fa4efbd0..29f0d0c8a 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
@@ -233,8 +233,7 @@ public class PCEnhancer {
      * repository.
      */
     public PCEnhancer(OpenJPAConfiguration conf, Class<?> type) {
-        this(conf, AccessController.doPrivileged(J2DoPrivHelper
-                                                         .loadProjectClassAction(new Project(), type)),
+        this(conf, AccessController.doPrivileged(SerpPrivacyHelper.loadProjectClassAction(new Project(), type)),
              (MetaDataRepository) null);
     }
 
@@ -244,8 +243,7 @@ public class PCEnhancer {
      * and then loading from <code>conf</code>'s repository.
      */
     public PCEnhancer(OpenJPAConfiguration conf, ClassMetaData meta) {
-        this(conf, AccessController.doPrivileged(J2DoPrivHelper
-                                                         .loadProjectClassAction(new Project(), meta.getDescribedType())),
+        this(conf, AccessController.doPrivileged(SerpPrivacyHelper.loadProjectClassAction(new Project(), meta.getDescribedType())),
              meta.getRepository());
     }
 
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
new file mode 100644
index 000000000..7ffdab287
--- /dev/null
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/SerpPrivacyHelper.java
@@ -0,0 +1,97 @@
+/*
+ * 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.enhance;
+
+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;
+
+/**
+ *
+ * @Deprecated just for getting rid of Serp in one place
+ */
+public class SerpPrivacyHelper extends J2DoPrivHelper {
+
+    /**
+     * Return a PrivilegeAction object for new BCClassLoader().
+     *
+     * Requires security policy:
+     *   'permission java.lang.RuntimePermission "createClassLoader";'
+     *
+     * @return BCClassLoader
+     */
+    public static PrivilegedAction<BCClassLoader> newBCClassLoaderAction(
+            final Project project, final ClassLoader parent) {
+        return new PrivilegedAction<BCClassLoader>() {
+            @Override
+            public BCClassLoader run() {
+                return new BCClassLoader(project, parent);
+            }
+        };
+    }
+
+    public static PrivilegedAction<BCClassLoader> newBCClassLoaderAction(
+        final Project project) {
+        return new PrivilegedAction<BCClassLoader>() {
+            @Override
+            public BCClassLoader run() {
+                return new BCClassLoader(project);
+            }
+        };
+    }
+
+    /**
+     * 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 a94946da4..11324f9bc 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
@@ -28,6 +28,7 @@ import java.util.Set;
 import java.util.WeakHashMap;
 
 import org.apache.openjpa.enhance.PCEnhancer;
+import org.apache.openjpa.enhance.SerpPrivacyHelper;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.lib.util.StringUtil;
@@ -81,18 +82,18 @@ class InterfaceImplGenerator {
         ClassLoader parentLoader = AccessController.doPrivileged(
             J2DoPrivHelper.getClassLoaderAction(iface));
         BCClassLoader loader = AccessController
-            .doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(_project,
-                parentLoader));
+            .doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(_project,
+                                                                   parentLoader));
         BCClassLoader enhLoader = AccessController
-            .doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(_enhProject,
-                parentLoader));
+            .doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(_enhProject,
+                                                                   parentLoader));
         BCClass bc = _project.loadClass(getClassName(meta));
         bc.declareInterface(iface);
         ClassMetaData sup = meta.getPCSuperclassMetaData();
         if (sup != null) {
             bc.setSuperclass(sup.getInterfaceImpl());
             enhLoader = AccessController
-                .doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(
+                .doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(
                     _enhProject, AccessController
                         .doPrivileged(J2DoPrivHelper.getClassLoaderAction(sup
                             .getInterfaceImpl()))));
diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java b/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java
index 5073e5b6a..e72b4f5b5 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/util/GeneratedClasses.java
@@ -20,6 +20,7 @@ package org.apache.openjpa.util;
 
 import java.security.AccessController;
 
+import org.apache.openjpa.enhance.SerpPrivacyHelper;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
 
 import serp.bytecode.BCClass;
@@ -60,7 +61,7 @@ public class GeneratedClasses {
      */
     public static Class loadBCClass(BCClass bc, ClassLoader loader) {
         BCClassLoader bcloader = AccessController
-                .doPrivileged(J2DoPrivHelper.newBCClassLoaderAction(bc
+                .doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(bc
                         .getProject(), loader));
         try {
             Class c = Class.forName(bc.getName(), true, bcloader);
diff --git a/openjpa-lib/pom.xml b/openjpa-lib/pom.xml
index abaddc10b..b65e00098 100644
--- a/openjpa-lib/pom.xml
+++ b/openjpa-lib/pom.xml
@@ -70,8 +70,9 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>net.sourceforge.serp</groupId>
-            <artifactId>serp</artifactId>
+            <groupId>org.apache.xbean</groupId>
+            <artifactId>xbean-asm9-shaded</artifactId>
+            <version>${xbean.version}</version>
         </dependency>
         <dependency>
             <groupId>jakarta.validation</groupId>
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassAnnotationMetaDataFilter.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassAnnotationMetaDataFilter.java
index 4dbe4ec90..2a35d8bf8 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassAnnotationMetaDataFilter.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassAnnotationMetaDataFilter.java
@@ -19,11 +19,17 @@
 package org.apache.openjpa.lib.meta;
 
 import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
 
 import org.apache.openjpa.lib.log.Log;
 import org.apache.openjpa.lib.util.Localizer;
+import org.apache.xbean.asm9.AnnotationVisitor;
+import org.apache.xbean.asm9.ClassReader;
+import org.apache.xbean.asm9.ClassVisitor;
+import org.apache.xbean.asm9.Opcodes;
+import org.apache.xbean.asm9.Type;
 
-import serp.bytecode.lowlevel.ConstantPoolTable;
 
 /**
  * Filter that looks for classes with one of a set of annotations.
@@ -34,10 +40,9 @@ import serp.bytecode.lowlevel.ConstantPoolTable;
  */
 public class ClassAnnotationMetaDataFilter implements MetaDataFilter {
 
-    private final String[] _annos;
+    private final Set<String> _annos;
 
-    private static final Localizer _loc = Localizer.forPackage
-        (ClassAnnotationMetaDataFilter.class);
+    private static final Localizer _loc = Localizer.forPackage(ClassAnnotationMetaDataFilter.class);
     private Log _log = null;
 
     /**
@@ -51,153 +56,26 @@ public class ClassAnnotationMetaDataFilter implements MetaDataFilter {
      * Constructor; supply annotations to match against.
      */
     public ClassAnnotationMetaDataFilter(Class<?>[] annos) {
-        _annos = new String[annos.length];
-        for (int i = 0; i < annos.length; i++)
-            _annos[i] = "L" + annos[i].getName().replace('.', '/') + ";";
+        _annos = new HashSet<>();
+        for (Class<?> anno : annos) {
+            _annos.add(Type.getDescriptor(anno));
+        }
     }
 
     @Override
     public boolean matches(Resource rsrc) throws IOException {
-        if (_annos.length == 0 || !rsrc.getName().endsWith(".class"))
+        if (_annos.isEmpty() || !rsrc.getName().endsWith(".class")) {
             return false;
-
-        try {
-            ConstantPoolTable table = new ConstantPoolTable(rsrc.getContent());
-            int idx = table.getEndIndex();
-            idx += 6; // skip access, cls, super
-
-            // skip interfaces
-            int interfaces = table.readUnsignedShort(idx);
-            idx += 2 + interfaces * 2;
-
-            // skip fields and methods
-            int fields = table.readUnsignedShort(idx);
-            idx += 2;
-            for (int i = 0; i < fields; i++)
-                idx += skipFieldOrMethod(table, idx);
-            int methods = table.readUnsignedShort(idx);
-            idx += 2;
-            for (int i = 0; i < methods; i++)
-                idx += skipFieldOrMethod(table, idx);
-
-            // look for annotation attrs
-            int attrs = table.readUnsignedShort(idx);
-            idx += 2;
-            int name;
-            for (int i = 0; i < attrs; i++) {
-                name = table.readUnsignedShort(idx);
-                idx += 2;
-                if ("RuntimeVisibleAnnotations".equals(table.readString
-                    (table.get(name))))
-                    return matchAnnotations(table, idx + 4);
-                idx += 4 + table.readInt(idx);
-            }
-        } catch (ArrayIndexOutOfBoundsException e) {
-            /*
-             * This ArrayIndexOutOfBoundsException indicates an incorrectly
-             * formed .class file. We will eat the exception, log a trace
-             * message (if a log exists), and return "false" to indicate there
-             * was no match.
-             */
-            Error cfe = new ClassFormatError(rsrc.getName());
-            cfe.initCause(e);
-            if (_log != null && _log.isTraceEnabled())
-                _log.trace(_loc.get("class-arg", rsrc.getName()), cfe);
         }
-        return false;
-    }
 
-    /**
-     * Return whether the given annotations match our candidates.
-     */
-    private boolean matchAnnotations(ConstantPoolTable table, int idx) {
-        int annos = table.readUnsignedShort(idx);
-        idx += 2;
-
-        int type;
-        int props;
-        for (int i = 0; i < annos; i++) {
-            type = table.readUnsignedShort(idx);
-            idx += 2;
-            if (matchAnnotation(table.readString(table.get(type))))
-                return true;
-
-            props = table.readUnsignedShort(idx);
-            idx += 2;
-            for (int j = 0; j < props; j++) {
-                idx += 2; // name
-                idx += skipAnnotationPropertyValue(table, idx);
-            }
-        }
-        return false;
-    }
+        ClassReader cr = new ClassReader(rsrc.getContent());
+        final MatchAnnotationScanner classVisitor = new MatchAnnotationScanner(Opcodes.ASM9);
+        cr.accept(classVisitor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
 
-    /**
-     * Return whether the given annotation matches our candidates.
-     */
-    private boolean matchAnnotation(String name) {
-        for (String anno : _annos)
-            if (name.equals(anno))
-                return true;
-        return false;
+        return classVisitor.matches;
     }
 
-    /**
-     * Skip an annotation property value, returning the number of bytes skipped.
-     */
-    private static int skipAnnotationPropertyValue(ConstantPoolTable table,
-        int idx) {
-        int skipped = 0;
-        switch (table.readByte(idx + skipped++)) {
-            case 'Z': // bool
-            case 'B': // byte
-            case 'C': // char
-            case 'D': // double
-            case 'F': // float
-            case 'I': // int
-            case 'J': // long
-            case 'S': // short
-            case 's': // string
-            case 'c': // class
-                skipped += 2;
-                break;
-            case 'e': // enum ptr
-                skipped += 4;
-                break;
-            case '[': // array
-                int size = table.readUnsignedShort(idx + skipped);
-                skipped += 2;
-                for (int i = 0; i < size; i++)
-                    skipped +=
-                        skipAnnotationPropertyValue(table, idx + skipped);
-                break;
-            case '@': // anno
-                skipped += 2; // type
-                int props = table.readUnsignedShort(idx + skipped);
-                skipped += 2;
-                for (int j = 0; j < props; j++) {
-                    skipped += 2; // name
-                    skipped +=
-                        skipAnnotationPropertyValue(table, idx + skipped);
-                }
-                break;
-        }
-        return skipped;
-    }
 
-    /**
-     * Skip the current field or method, returning the number of bytes skipped.
-     */
-    private static int skipFieldOrMethod(ConstantPoolTable table, int idx) {
-        int attrs = table.readUnsignedShort(idx + 6);
-        int skipped = 8;
-        int len;
-        for (int i = 0; i < attrs; i++) {
-            len = table.readInt(idx + skipped + 2);
-            skipped += 6 + len;
-        }
-        return skipped;
-    }
 
     public Log getLog() {
         return _log;
@@ -206,4 +84,20 @@ public class ClassAnnotationMetaDataFilter implements MetaDataFilter {
     public void setLog(Log _log) {
         this._log = _log;
     }
+
+    public class MatchAnnotationScanner extends ClassVisitor {
+        boolean matches = false;
+
+        public MatchAnnotationScanner(int api) {
+            super(api);
+        }
+
+        @Override
+        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
+            if (visible && _annos.contains(descriptor)) {
+                matches = true;
+            }
+            return super.visitAnnotation(descriptor, visible);
+        }
+    }
 }
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassArgParser.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassArgParser.java
index 5c4c7ba35..4b8833c54 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassArgParser.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/meta/ClassArgParser.java
@@ -40,8 +40,10 @@ import org.apache.openjpa.lib.util.ClassUtil;
 import org.apache.openjpa.lib.util.Files;
 import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.lib.util.Localizer;
+import org.apache.xbean.asm9.ClassReader;
+import org.apache.xbean.asm9.ClassVisitor;
+import org.apache.xbean.asm9.Opcodes;
 
-import serp.bytecode.lowlevel.ConstantPoolTable;
 
 /**
  * Parser used to resolve arguments into java classes.
@@ -253,11 +255,11 @@ public class ClassArgParser {
      * Parse the names in the given metadata iterator stream, closing the
      * stream on completion.
      */
-    private void appendTypeNames(Object source, InputStream in,
-        List<String> names) throws IOException {
+    private void appendTypeNames(Object source, InputStream in, List<String> names) throws IOException {
         try {
-            if (source.toString().endsWith(".class"))
-                names.add(getFromClass(in));
+            if (source.toString().endsWith(".class")) {
+                names.add(getNameFromClass(in));
+            }
             names.addAll(getFromMetaData(new InputStreamReader(in)));
         } finally {
             try {
@@ -300,30 +302,31 @@ public class ClassArgParser {
     private String getFromClassFile(File file) throws IOException {
         FileInputStream fin = null;
         try {
-            fin = AccessController.doPrivileged(
-                J2DoPrivHelper.newFileInputStreamAction(file));
-            return getFromClass(fin);
+            fin = AccessController.doPrivileged(J2DoPrivHelper.newFileInputStreamAction(file));
+            return getNameFromClass(fin);
         } catch (PrivilegedActionException pae) {
             throw (FileNotFoundException) pae.getException();
         } finally {
-            if (fin != null)
+            if (fin != null) {
                 try {
                     fin.close();
-                } catch (IOException ioe) {
                 }
+                catch (IOException ioe) {
+                }
+            }
         }
     }
 
     /**
      * Returns the class name in the given .class bytecode.
      */
-    private String getFromClass(InputStream in) throws IOException {
-        ConstantPoolTable table = new ConstantPoolTable(in);
-        int idx = table.getEndIndex();
-        idx += 2; // access flags
-        int clsEntry = table.readUnsignedShort(idx);
-        int utfEntry = table.readUnsignedShort(table.get(clsEntry));
-        return table.readString(table.get(utfEntry)).replace('/', '.');
+    private String getNameFromClass(InputStream in) throws IOException {
+
+        ClassReader cr = new ClassReader(in);
+        final ClassNameScanner classNameScanner = new ClassNameScanner(Opcodes.ASM9);
+        cr.accept(classNameScanner, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+
+        return classNameScanner.className;
     }
 
     /**
@@ -620,4 +623,19 @@ public class ClassArgParser {
             buf.append((char) ch);
         }
     }
+
+
+    public class ClassNameScanner extends ClassVisitor {
+        String className = null;
+
+        public ClassNameScanner(int api) {
+            super(api);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            this.className = name.replace("/", ".");
+            super.visit(version, access, name, signature, superName, interfaces);
+        }
+    }
 }
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java
index 96eb36610..721ad71eb 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/J2DoPrivHelper.java
@@ -54,12 +54,6 @@ import jakarta.validation.Validation;
 import jakarta.validation.Validator;
 import jakarta.validation.ValidatorFactory;
 
-import serp.bytecode.BCClass;
-import serp.bytecode.BCClassLoader;
-import serp.bytecode.BCField;
-import serp.bytecode.Code;
-import serp.bytecode.FieldInstruction;
-import serp.bytecode.Project;
 
 /**
  * Helper class to obtain the Privilege(Exception)Action object to perform
@@ -108,12 +102,6 @@ import serp.bytecode.Project;
  * <li>URL.openStream
  * <li>URLConnection.getContent
  * <li>ZipFile new
- * <li>serp.bytecode.Code new
- * <li>serp.bytecode.BCClassLoader new
- * <li>serp.bytecode.BCClass.write
- * <li>serp.bytecode.BCClass.getFields
- * <li>serp.bytecode.FieldInstruction.getField
- * <li>serp.bytecode.Project.loadClass
  * <li>AnnotatedElement.getAnnotations
  * <li>AnnotatedElement.getDeclaredAnnotations
  * <li>AnnotatedElement.isAnnotationPresent
@@ -1068,22 +1056,6 @@ public abstract class J2DoPrivHelper {
         };
     }
 
-    /**
-     * Return a PrivilegeAction object for new serp.bytecode.Code().
-     *
-     * Requires security policy:
-     *   'permission java.lang.RuntimePermission "getClassLoader";'
-     *
-     * @return serp.bytecode.Code
-     */
-    public static PrivilegedAction<Code> newCodeAction() {
-        return new PrivilegedAction<Code>() {
-            @Override
-            public Code run() {
-                return new Code();
-            }
-        };
-    }
 
     /**
      * Return a PrivilegeAction object for new TemporaryClassLoader().
@@ -1121,106 +1093,6 @@ public abstract class J2DoPrivHelper {
         };
     }
 
-    /**
-     * Return a PrivilegeAction object for new BCClassLoader().
-     *
-     * Requires security policy:
-     *   'permission java.lang.RuntimePermission "createClassLoader";'
-     *
-     * @return BCClassLoader
-     */
-    public static PrivilegedAction<BCClassLoader> newBCClassLoaderAction(
-        final Project project, final ClassLoader parent) {
-        return new PrivilegedAction<BCClassLoader>() {
-            @Override
-            public BCClassLoader run() {
-                return new BCClassLoader(project, parent);
-            }
-        };
-    }
-
-    public static PrivilegedAction<BCClassLoader> newBCClassLoaderAction(
-        final Project project) {
-        return new PrivilegedAction<BCClassLoader>() {
-            @Override
-            public BCClassLoader run() {
-                return new BCClassLoader(project);
-            }
-        };
-    }
-
-    /**
-     * 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 FieldInstruction.getField().
-     *
-     * Requires security policy:
-     *   'permission java.lang.RuntimePermission "getClassLoader";'
-     *
-     * @return BCField
-     */
-    public static PrivilegedAction<BCField> getFieldInstructionFieldAction
-    (
-        final FieldInstruction instruction) {
-        return new PrivilegedAction<BCField>() {
-            @Override
-            public BCField run() {
-                return instruction.getField();
-            }
-        };
-    }
-
-    /**
-     * 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);
-            }
-        };
-    }
-
-    /**
-     * Return a PrivilegeAction object for Project.loadClass().
-     *
-     * Requires security policy:
-     *   'permission java.lang.RuntimePermission "getClassLoader";'
-     *
-     * @return BCClass
-     */
-    public static PrivilegedAction<BCClass> loadProjectClassAction(
-        final Project project, final String clazzName) {
-        return new PrivilegedAction<BCClass>() {
-            @Override
-            public BCClass run() {
-                return project.loadClass(clazzName);
-            }
-        };
-    }
 
     /**
      * Return a PrivilegeAction object for AnnotatedElement.getAnnotations().
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/JavaVersions.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/JavaVersions.java
index ae402e5d5..222770d6e 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/JavaVersions.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/JavaVersions.java
@@ -34,7 +34,7 @@ import java.security.AccessController;
 public class JavaVersions {
 
     /**
-     * Java version; one of 2, 3, 4, 5, 6, or 7.
+     * Java version; one of 2, 3, 4, 5, 6, 7, or later.
      */
     public static final int VERSION;
 
@@ -57,8 +57,9 @@ public class JavaVersions {
             VERSION = 7;
         else if ("1.8".equals(specVersion))
             VERSION = 8;
-        else
-            VERSION = 9; // maybe someday...
+        else {
+            VERSION = Integer.parseInt(specVersion);
+        }
     }
 
     /**
diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/TemporaryClassLoader.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/TemporaryClassLoader.java
index 1c3881790..7bd16d182 100644
--- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/TemporaryClassLoader.java
+++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/util/TemporaryClassLoader.java
@@ -22,7 +22,10 @@ import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 
-import serp.bytecode.lowlevel.ConstantPoolTable;
+import org.apache.xbean.asm9.ClassReader;
+import org.apache.xbean.asm9.ClassVisitor;
+import org.apache.xbean.asm9.Opcodes;
+
 
 /**
  * ClassLoader implementation that allows classes to be temporarily
@@ -73,10 +76,15 @@ public class TemporaryClassLoader extends ClassLoader {
                 bout.write(b, 0, n))
                 ;
             byte[] classBytes = bout.toByteArray();
+
             // To avoid classloader issues with the JVM (Sun and IBM), we
             // will not load Enums via the TemporaryClassLoader either.
             // Reference JIRA Issue OPENJPA-646 for more information.
-            if (isAnnotation(classBytes) || isEnum(classBytes)) {
+            ClassReader cr = new ClassReader(classBytes);
+            final AccessScanner accessScanner = new AccessScanner(Opcodes.ASM9);
+            cr.accept(accessScanner, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+
+            if (accessScanner.isAnnotation || accessScanner.isEnum) {
                 try {
                     Class<?> frameworkClass = Class.forName(name, resolve,
                             getClass().getClassLoader());
@@ -98,27 +106,21 @@ public class TemporaryClassLoader extends ClassLoader {
         }
     }
 
-    /**
-     * Fast-parse the given class bytecode to determine if it is an
-     * annotation class.
-     */
-    private static boolean isAnnotation(byte[] b) {
-        if (JavaVersions.VERSION < 5)
-            return false;
-        int idx = ConstantPoolTable.getEndIndex(b);
-        int access = ConstantPoolTable.readUnsignedShort(b, idx);
-        return (access & 0x2000) != 0; // access constant for annotation type
-    }
 
-    /**
-     * Fast-parse the given class bytecode to determine if it is an
-     * enum class.
-     */
-    private static boolean isEnum(byte[] b) {
-        if (JavaVersions.VERSION < 5)
-            return false;
-        int idx = ConstantPoolTable.getEndIndex(b);
-        int access = ConstantPoolTable.readUnsignedShort(b, idx);
-        return (access & 0x4000) != 0; // access constant for enum type
+    public class AccessScanner extends ClassVisitor {
+        boolean isEnum = false;
+        boolean isAnnotation = false;
+
+        public AccessScanner(int api) {
+            super(api);
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
+            isEnum = (access & Opcodes.ACC_ENUM) > 0;
+            isAnnotation = (access & Opcodes.ACC_ANNOTATION) > 0;
+
+            super.visit(version, access, name, signature, superName, interfaces);
+        }
     }
 }
diff --git a/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/StringUtilTest.java b/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/StringUtilTest.java
index 6fd48c54d..5380d44c2 100644
--- a/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/StringUtilTest.java
+++ b/openjpa-lib/src/test/java/org/apache/openjpa/lib/util/StringUtilTest.java
@@ -193,8 +193,6 @@ public class StringUtilTest {
         long start = System.nanoTime();
         for (int i = 1; i < 10000000; i++) {
             StringUtil.split(val, "sd", 0);
-            //X val.split("sd");
-            //X serp.util.Strings.split(val, "sd", 0);
         }
 
         long stop = System.nanoTime();
diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java
index 67597d454..38dc3cdfb 100644
--- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java
+++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java
@@ -51,8 +51,7 @@ public class TestEnhancementWithMultiplePUs
                 getClass().getClassLoader()));
         Project project = new Project();
 
-        String className =
-            "org.apache.openjpa.enhance.UnenhancedBootstrapInstance";
+        String className = "org.apache.openjpa.enhance.UnenhancedBootstrapInstance";
         BCClass bc = assertNotPC(loader, project, className);
 
         PCEnhancer enhancer = new PCEnhancer(conf, bc, repos, loader);
@@ -62,8 +61,7 @@ public class TestEnhancementWithMultiplePUs
         assertTrue(enhancer.getPCBytecode().getClassNode().interfaces.contains(Type.getInternalName(PersistenceCapable.class)));
     }
 
-    private BCClass assertNotPC(ClassLoader loader, Project project,
-        String className) {
+    private BCClass assertNotPC(ClassLoader loader, Project project, String className) {
         BCClass bc = project.loadClass(className, loader);
         assertFalse(className + " must not be enhanced already; it was.",
             Arrays.asList(bc.getInterfaceNames()).contains(