OPENJPA-2911 Bridge from BCClass <-> ASM ClassNode

This will allow us to smoothly migrate from Serp to ASM
This commit is contained in:
Mark Struberg 2023-06-01 14:21:05 +02:00
parent d13b85b139
commit 032c6fc7fe
6 changed files with 112 additions and 23 deletions

View File

@ -142,9 +142,9 @@ public final class SQLBuffer
if (!paramOnly) {
if (sqlIndex == _sql.length())
_sql.append(buf._sql.toString());
_sql.append(buf._sql);
else
_sql.insert(sqlIndex, buf._sql.toString());
_sql.insert(sqlIndex, buf._sql);
}
if (buf._params != null) {
@ -326,7 +326,7 @@ public final class SQLBuffer
if (o == null)
_sql.append("NULL");
else if (o instanceof Raw)
_sql.append(o.toString());
_sql.append(o);
else {
Class<?> type = Filters.wrap(o.getClass());
if (useParamToken || !validParamLiteralType(type)) {
@ -366,7 +366,7 @@ public final class SQLBuffer
} else if ( type == Character.class ) {
if (_dict.storeCharsAsNumbers) {
_sql.append(Integer.toString((Character) o));
_sql.append(o);
} else {
_sql.append("'" + o.toString().replace("'", "''") + "'");
}
@ -375,7 +375,7 @@ public final class SQLBuffer
// We store B(b)ooleans as ints. Convert
_sql.append(_dict.getBooleanRepresentation().getRepresentation(b));
} else {
_sql.append(o.toString());
_sql.append(o);
}
}
}

View File

@ -96,12 +96,15 @@ import org.apache.openjpa.util.ShortId;
import org.apache.openjpa.util.StringId;
import org.apache.openjpa.util.UserException;
import org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import org.apache.openjpa.util.asm.ClassWriterTracker;
import org.apache.xbean.asm9.Opcodes;
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.InsnNode;
import org.apache.xbean.asm9.tree.LdcInsnNode;
import org.apache.xbean.asm9.tree.MethodNode;
import org.apache.xbean.asm9.tree.VarInsnNode;
@ -289,8 +292,7 @@ public class PCEnhancer {
* @param loader the environment classloader to use for loading
* classes and resources.
*/
public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
MetaDataRepository repos, ClassLoader loader) {
public PCEnhancer(OpenJPAConfiguration conf, BCClass type, MetaDataRepository repos, ClassLoader loader) {
_managedType = type;
_pc = type;
@ -326,8 +328,7 @@ public class PCEnhancer {
*
* @since 1.1.0
*/
public PCEnhancer(MetaDataRepository repos, BCClass type,
ClassMetaData meta) {
public PCEnhancer(MetaDataRepository repos, BCClass type, ClassMetaData meta) {
_managedType = type;
_pc = type;
@ -373,14 +374,6 @@ public class PCEnhancer {
return className;
}
/**
* Constructor. Supply configuration, type, and metadata.
*/
public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
ClassMetaData meta) {
this(conf, type, meta.getRepository());
}
/**
* Return the bytecode representation of the persistence-capable class
* being manipulated.
@ -3076,10 +3069,17 @@ public class PCEnhancer {
*/
private void enhanceClass() {
// make the class implement PersistenceCapable
_pc.declareInterface(PCTYPE);
//_pc.declareInterface(PCTYPE);
final ClassNodeTracker classNodeTracker = AsmHelper.toClassNode(_pc);
// make the class implement PersistenceCapable
classNodeTracker.getClassNode().interfaces.add(Type.getInternalName(PCTYPE));
// add a version stamp
addGetEnhancementContractVersionMethod();
addGetEnhancementContractVersionMethod(classNodeTracker);
AsmHelper.readIntoBCClass(classNodeTracker, _pc);
// find the default constructor
BCMethod method = _pc.getDeclaredMethod("<init>", (String[]) null);
@ -4893,6 +4893,17 @@ public class PCEnhancer {
return setter;
}
private void addGetEnhancementContractVersionMethod(ClassNodeTracker cnt) {
MethodNode methodNode = new MethodNode(Opcodes.ACC_PUBLIC,
PRE + "GetEnhancementContractVersion",
Type.getMethodDescriptor(Type.INT_TYPE),
null, null);
methodNode.instructions.add(new LdcInsnNode(ENHANCER_VERSION));
methodNode.instructions.add(new InsnNode(Opcodes.IRETURN));
cnt.getClassNode().methods.add(methodNode);
}
@Deprecated //X TODO REMOVE
private void addGetEnhancementContractVersionMethod() {
// public int getEnhancementContractVersion()
BCMethod method = _pc.declareMethod(PRE +

View File

@ -124,7 +124,7 @@ class InterfaceImplGenerator {
iface)).setFatal(true);
try {
// load the Class<?> for real.
impl = Class.forName(bc.getName(), true, enhLoader);
impl = Class.forName(enhancer.getPCBytecode().getName(), true, enhLoader);
} catch (Throwable t) {
throw new InternalException(_loc.get("interface-load2", iface,
enhLoader), t).setFatal(true);

View File

@ -19,6 +19,7 @@ package org.apache.openjpa.util.asm;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.xbean.asm9.ClassReader;
@ -78,7 +79,7 @@ public final class AsmHelper {
}
/**
* temporary helper class to convert BCClass to ASM
* 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) {
@ -102,10 +103,44 @@ public final class AsmHelper {
return bcClass;
}
/**
* temporary helper class to convert BCClass to ASM ClassNode
* @deprecated must get removed when done with migrating from Serp to ASM
*/
public static ClassNodeTracker toClassNode(BCClass bcClass) {
ClassReader cr = new ClassReader(bcClass.toByteArray());
ClassNode classNode = new ClassNode(Opcodes.ASM9);
cr.accept(classNode, 0);
return new ClassNodeTracker(classNode, bcClass.getClassLoader());
}
/**
* Take the changes from ClassNodeTracker and read it into the given BCClass instance.
* Effectively replace all the content of BCClass with the content from our ClassNode
*/
public static void readIntoBCClass(ClassNodeTracker cnt, BCClass bcClass) {
// sadly package scoped
try {
Method readMethod = BCClass.class.getDeclaredMethod("read", InputStream.class, ClassLoader.class);
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cnt.getClassNode().accept(cw);
final byte[] classBytes = cw.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(classBytes);
readMethod.setAccessible(true);
readMethod.invoke(bcClass, bais, bcClass.getClassLoader());
}
catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
}
/**
* Calclates the proper Return instruction opcode for the given class
*
*
* @param type the type to get returned
* @return the proper Opcode RETURN, ARETURN, IRETURN, etc
*/

View File

@ -0,0 +1,42 @@
/*
* 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.util.asm;
import org.apache.xbean.asm9.tree.ClassNode;
/**
* Helper class to transit from BCClass to ASM
*
* @author <a href="mailto:struberg@apache.org">Mark Struberg</a>
*/
public class ClassNodeTracker {
private final ClassNode classNode;
private final ClassLoader cl;
public ClassNodeTracker(ClassNode classNode, ClassLoader cl) {
this.classNode = classNode;
this.cl = cl;
}
public ClassNode getClassNode() {
return classNode;
}
public ClassLoader getClassLoader() {
return cl;
}
}

View File

@ -56,7 +56,8 @@ public class TestEnhancementWithMultiplePUs
PCEnhancer enhancer = new PCEnhancer(conf, bc, repos, loader);
assertEquals(PCEnhancer.ENHANCE_PC, enhancer.run());
assertTrue(Arrays.asList(bc.getInterfaceNames()).contains(
assertTrue(Arrays.asList(enhancer.getPCBytecode().getInterfaceNames()).contains(
PersistenceCapable.class.getName()));
}