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 11367cfbeae7e71c22804fc7c1040989388ea5cb
Author: Mark Struberg <strub...@apache.org>
AuthorDate: Mon Jul 17 18:06:43 2023 +0200

    OPENJPA-2911 ByteCodeWriter with ASM
---
 .../openjpa/enhance/ManagedClassSubclasser.java    | 70 ++++++++++++----------
 .../org/apache/openjpa/enhance/PCEnhancer.java     | 36 +++++------
 .../openjpa/util/ClassLoaderProxyService.java      |  1 +
 .../org/apache/openjpa/util/GeneratedClasses.java  |  2 +-
 .../org/apache/openjpa/util/asm/AsmHelper.java     |  9 +++
 .../apache/openjpa/util/asm/BytecodeWriter.java    |  2 +-
 .../enhance/TestEnhancementWithMultiplePUs.java    | 24 ++++----
 7 files changed, 77 insertions(+), 67 deletions(-)

diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
 
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
index 2fc77a346..cde3f0412 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ManagedClassSubclasser.java
@@ -18,9 +18,10 @@
  */
 package org.apache.openjpa.enhance;
 
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.StandardOpenOption;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -32,8 +33,8 @@ import java.util.Set;
 
 import org.apache.openjpa.conf.OpenJPAConfiguration;
 import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.util.asm.AsmHelper;
 import org.apache.openjpa.util.asm.BytecodeWriter;
-import org.apache.openjpa.lib.util.Files;
 import org.apache.openjpa.lib.util.Localizer;
 import org.apache.openjpa.lib.util.Localizer.Message;
 import org.apache.openjpa.meta.AccessCode;
@@ -46,8 +47,7 @@ import org.apache.openjpa.util.ImplHelper;
 import org.apache.openjpa.util.InternalException;
 import org.apache.openjpa.util.MetaDataException;
 import org.apache.openjpa.util.UserException;
-
-import serp.bytecode.BCClass;
+import org.apache.openjpa.util.asm.ClassNodeTracker;
 
 /**
  * Redefines the method bodies of existing unenhanced classes to make them
@@ -65,7 +65,7 @@ public class ManagedClassSubclasser {
      * OpenJPA to handle new instances of the unenhanced type. If this is
      * invoked in a Java 6 environment, this method will redefine the methods
      * for each class in the argument list such that field accesses are
-     * intercepted in-line. If invoked in a Java 5 environment, this
+     * intercepted in-line. If invoked in a Java 5 environment or very new 
Java versions, this
      * redefinition is not possible; in these contexts, when using field
      * access, OpenJPA will need to do state comparisons to detect any change
      * to any instance at any time, and when using property access, OpenJPA
@@ -136,8 +136,8 @@ public class ManagedClassSubclasser {
 
             enhancer.setBytecodeWriter(new BytecodeWriter() {
                 @Override
-                public void write(BCClass bc) throws IOException {
-                    ManagedClassSubclasser.write(bc, enhancer, map, c, subs, 
ints);
+                public void write(ClassNodeTracker cnt) throws IOException {
+                    ManagedClassSubclasser.write(cnt, enhancer, map, c, subs, 
ints);
                 }
             });
             if (redefine) {
@@ -174,9 +174,9 @@ public class ManagedClassSubclasser {
             }
         }
 
-        if (unspecified != null && !unspecified.isEmpty())
-            throw new UserException(_loc.get("unspecified-unenhanced-types", 
Exceptions.toClassNames(classes),
-                    unspecified));
+        if (unspecified != null && !unspecified.isEmpty()) {
+            throw new UserException(_loc.get("unspecified-unenhanced-types", 
Exceptions.toClassNames(classes), unspecified));
+        }
 
         ClassRedefiner.redefineClasses(conf, map);
         for (Class<?> cls : map.keySet()) {
@@ -269,55 +269,61 @@ public class ManagedClassSubclasser {
         }
     }
 
-    private static void write(BCClass bc, PCEnhancer enhancer,
-        Map<Class<?>, byte[]> map, Class<?> cls, List<Class<?>> subs, 
List<Class<?>> ints)
+    private static void write(ClassNodeTracker cnt, PCEnhancer enhancer, 
Map<Class<?>, byte[]> map,
+                              Class<?> cls, List<Class<?>> subs, 
List<Class<?>> ints)
         throws IOException {
 
-        if (bc == enhancer.getManagedTypeBytecode()) {
+        if (cnt == enhancer.getManagedTypeBytecode()) {
             // if it was already defined, don't put it in the map,
             // but do set the metadata accordingly.
             if (enhancer.isAlreadyRedefined())
-                ints.add(bc.getType());
+                ints.add(cls);
             else {
-                ByteArrayOutputStream baos = new ByteArrayOutputStream();
-                AsmAdaptor.write(bc, baos);
-                map.put(bc.getType(), baos.toByteArray());
-                debugBytecodes(bc);
+                final byte[] byteArray = AsmHelper.toByteArray(cnt);
+                map.put(cls, byteArray);
+                debugBytecodes(cnt, byteArray);
             }
         } else {
             if (!enhancer.isAlreadySubclassed()) {
-                debugBytecodes(bc);
+                final byte[] byteArray = AsmHelper.toByteArray(cnt);
+                debugBytecodes(cnt, byteArray);
 
                 // this is the new subclass
-                ClassLoader loader = GeneratedClasses.getMostDerivedLoader(
-                    cls, PersistenceCapable.class);
-                subs.add(GeneratedClasses.loadBCClass(bc, loader));
+                ClassLoader loader = 
GeneratedClasses.getMostDerivedLoader(cls, PersistenceCapable.class);
+                String className = cnt.getClassNode().name.replace("/", ".");
+                final Class subclass = 
GeneratedClasses.loadAsmClass(className, byteArray, cls, loader);
+                try {
+                    // Ugly workaround to trigger clinit static initializer 
block :(
+                    subclass.newInstance();
+                }
+                catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+                subs.add(subclass);
             }
         }
     }
 
-    public static void debugBytecodes(BCClass bc) throws IOException {
+    public static void debugBytecodes(ClassNodeTracker cnt, byte[] classBytes) 
throws IOException {
         // Write the bytecodes to disk for debugging purposes.
-        if ("true".equals(System.getProperty(
-            ManagedClassSubclasser.class.getName() + ".dumpBytecodes")))
+        if 
("true".equals(System.getProperty(ManagedClassSubclasser.class.getName() + 
".dumpBytecodes")))
         {
             File tmp = new File(System.getProperty("java.io.tmpdir"));
             File dir = new File(tmp, "openjpa");
             dir = new File(dir, "pcsubclasses");
             dir.mkdirs();
-            dir = Files.getPackageFile(dir, bc.getPackageName(), true);
-            File f = new File(dir, bc.getClassName() + ".class");
+            File f = new File(dir, cnt.getClassNode().name + ".class");
+
             // START - ALLOW PRINT STATEMENTS
             System.err.println("Writing to " + f);
             // STOP - ALLOW PRINT STATEMENTS
-            AsmAdaptor.write(bc, f);
+
+            Files.write(f.toPath(), classBytes, StandardOpenOption.WRITE);
         }
     }
 
-    private static void setIntercepting(OpenJPAConfiguration conf,
-        ClassLoader envLoader, Class<?> cls) {
-        ClassMetaData meta = conf.getMetaDataRepositoryInstance()
-            .getMetaData(cls, envLoader, true);
+    private static void setIntercepting(OpenJPAConfiguration conf, ClassLoader 
envLoader, Class<?> cls) {
+        ClassMetaData meta = 
conf.getMetaDataRepositoryInstance().getMetaData(cls, envLoader, true);
         meta.setIntercepting(true);
     }
 
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 0dc51236d..d78299622 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
@@ -212,7 +212,6 @@ public class PCEnhancer {
 
     private final ClassMetaData _meta;
     private final Log _log;
-    private Collection _oids = null;
     private boolean _defCons = true;
     private boolean _redefine = false;
     private boolean _subclass = false;
@@ -389,8 +388,8 @@ public class PCEnhancer {
      * except when running the enhancer to redefine and subclass
      * existing persistent types.
      */
-    public BCClass getManagedTypeBytecode() {
-        return _managedType;
+    public ClassNodeTracker getManagedTypeBytecode() {
+        return managedType;
     }
 
     /**
@@ -641,46 +640,41 @@ public class PCEnhancer {
     /**
      * Write the generated bytecode.
      */
-    public void record()
-            throws IOException {
-        if (_managedType != _pc && getRedefine()) {
-            record(AsmHelper.toClassWriter(_managedType));
+    public void record() throws IOException {
+        if (managedType != pc && getRedefine()) {
+            record(managedType);
         }
 
-        record(AsmHelper.toClassWriter(_pc));
-
-        if (_oids != null)
-            for (Object oid : _oids) {
-                record(AsmHelper.toClassWriter((BCClass) oid));
-            }
+        record(pc);
     }
 
     /**
      * Write the given class.
      */
-    private void record(ClassWriterTracker cwt)
+    private void record(ClassNodeTracker cnt)
             throws IOException {
-        if (_writer != null)
-            _writer.write(AsmHelper.toBCClass(cwt));
+        if (_writer != null) {
+            _writer.write(cnt);
+        }
         else if (_dir == null) {
-            String name = cwt.getName().replace(".", "/");
-            ClassLoader cl = cwt.getClassLoader();
+            String name = cnt.getClassNode().name.replace(".", "/");
+            ClassLoader cl = cnt.getClassLoader();
             if (cl == null) {
                 cl = Thread.currentThread().getContextClassLoader();
             }
             final URL resource = cl.getResource(name + ".class");
             try (OutputStream out = new 
FileOutputStream(URLDecoder.decode(resource.getFile()))) {
-                out.write(cwt.getCw().toByteArray());
+                out.write(AsmHelper.toByteArray(cnt));
                 out.flush();
             }
         }
         else {
-            String name = cwt.getName().replace(".", "/") + ".class";
+            String name = cnt.getClassNode().name.replace(".", "/") + ".class";
             File targetFile = new File(_dir, name);
             if (!targetFile.getParentFile().exists()) {
                 targetFile.getParentFile().mkdirs();
             }
-            java.nio.file.Files.write(targetFile.toPath(), 
cwt.getCw().toByteArray());
+            java.nio.file.Files.write(targetFile.toPath(), 
AsmHelper.toByteArray(cnt));
         }
     }
 
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ClassLoaderProxyService.java
 
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ClassLoaderProxyService.java
index 654d06368..4ba872cae 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/ClassLoaderProxyService.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/ClassLoaderProxyService.java
@@ -106,6 +106,7 @@ public class ClassLoaderProxyService
                             definePackageFor(pck, protectionDomain);
                         }
                         existing = super.defineClass(proxyClassName, 
proxyBytes, 0, proxyBytes.length);
+
                         resolveClass(existing);
                         classes.put(key, existing);
                     }
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 b6ddf2565..5073e5b6a 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
@@ -56,7 +56,7 @@ public class GeneratedClasses {
 
     /**
      * Load the class represented by the given bytecode.
-     * @deprecated move to ASM
+     * @deprecated move to ASM {@link #loadAsmClass(String, byte[], Class, 
ClassLoader)}
      */
     public static Class loadBCClass(BCClass bc, ClassLoader loader) {
         BCClassLoader bcloader = AccessController
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 6bb378e3f..d86bb6b85 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
@@ -110,6 +110,15 @@ public final class AsmHelper {
         return cwt;
     }
 
+    /**
+     * Create a byte[] of that class represented by the ClassNodeTracker
+     */
+    public static byte[] toByteArray(ClassNodeTracker cnt) {
+        ClassWriter cw = new BCClassWriter(ClassWriter.COMPUTE_FRAMES, 
cnt.getClassLoader());
+        cnt.getClassNode().accept(cw);
+        return cw.toByteArray();
+    }
+
     /**
      * temporary helper class to convert ClassWriterTracker to BCClass
      * @deprecated must get removed when done with migrating from Serp to ASM
diff --git 
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/BytecodeWriter.java 
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/BytecodeWriter.java
index c69a72eb4..06af49c79 100644
--- 
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/BytecodeWriter.java
+++ 
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/BytecodeWriter.java
@@ -29,5 +29,5 @@ import serp.bytecode.BCClass;
  */
 public interface BytecodeWriter {
 
-    void write(BCClass type) throws IOException;
+    void write(ClassNodeTracker type) throws IOException;
 }
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 f139069e2..7189e7946 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
@@ -32,6 +32,8 @@ import org.apache.openjpa.lib.util.J2DoPrivHelper;
 import org.apache.openjpa.lib.util.Options;
 import org.apache.openjpa.meta.MetaDataRepository;
 import org.apache.openjpa.persistence.test.AbstractCachedEMFTestCase;
+import org.apache.openjpa.util.asm.ClassNodeTracker;
+import org.apache.xbean.asm9.Type;
 
 import serp.bytecode.BCClass;
 import serp.bytecode.Project;
@@ -84,9 +86,8 @@ public class TestEnhancementWithMultiplePUs
         Project project = new Project();
 
         // make sure that the class is not already enhanced for some reason
-        String className =
-            "org.apache.openjpa.enhance.UnenhancedBootstrapInstance";
-        BCClass bc = assertNotPC(loader, project, className);
+        String className = 
"org/apache/openjpa/enhance/UnenhancedBootstrapInstance";
+        assertNotPC(loader, project, className);
 
         // build up a writer that just stores to a list so that we don't
         // mutate the disk.
@@ -94,10 +95,9 @@ public class TestEnhancementWithMultiplePUs
         BytecodeWriter writer = new BytecodeWriter() {
 
             @Override
-            public void write(BCClass type) throws IOException {
-                assertTrue(Arrays.asList(type.getInterfaceNames()).contains(
-                    PersistenceCapable.class.getName()));
-                written.add(type.getName());
+            public void write(ClassNodeTracker cnt) throws IOException {
+                
assertTrue(cnt.getClassNode().interfaces.contains(Type.getInternalName(PersistenceCapable.class)));
+                written.add(cnt.getClassNode().name);
             }
         };
 
@@ -135,9 +135,9 @@ public class TestEnhancementWithMultiplePUs
         BytecodeWriter writer = new BytecodeWriter() {
 
             @Override
-            public void write(BCClass type) throws IOException {
-                
assertTrue(Arrays.asList(type.getInterfaceNames()).contains(PersistenceCapable.class.getName()));
-                written.add(type.getName());
+            public void write(ClassNodeTracker cnt) throws IOException {
+                
assertTrue(cnt.getClassNode().interfaces.contains(Type.getInternalName(PersistenceCapable.class)));
+                written.add(cnt.getClassNode().name);
             }
         };
 
@@ -156,8 +156,8 @@ public class TestEnhancementWithMultiplePUs
 
         // ensure that we do process the classes listed in the PUs
         assertTrue(written.contains(
-            "org.apache.openjpa.enhance.UnenhancedBootstrapInstance"));
+            "org/apache/openjpa/enhance/UnenhancedBootstrapInstance"));
         assertTrue(written.contains(
-            "org.apache.openjpa.enhance.UnenhancedBootstrapInstance2"));
+            "org/apache/openjpa/enhance/UnenhancedBootstrapInstance2"));
     }
 }

Reply via email to