OPENJPA-2911 move PCEnhancer off Serp

This commit is contained in:
Mark Struberg 2023-07-19 13:14:16 +02:00
parent dfaf8da48e
commit 0a81c3de7b
11 changed files with 209 additions and 134 deletions

View File

@ -29,6 +29,7 @@ import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.persistence.PersistenceMetaDataFactory;
import org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import org.apache.openjpa.util.asm.EnhancementProject;
import org.apache.xbean.asm9.AnnotationVisitor;
import org.apache.xbean.asm9.ClassReader;
import org.apache.xbean.asm9.Type;
@ -265,18 +266,16 @@ public class OpenJPADirectoriesEnhancer implements Runnable {
final Thread thread = Thread.currentThread();
final ClassLoader old = thread.getContextClassLoader();
thread.setContextClassLoader(tmpLoader);
try (final InputStream stream = new ByteArrayInputStream(classBytes)) {
try {
final PCEnhancer enhancer = new PCEnhancer(
repos.getConfiguration(),
new Project().loadClass(stream, tmpLoader),
new EnhancementProject().loadClass(classBytes, tmpLoader),
repos, tmpLoader);
if (enhancer.run() == PCEnhancer.ENHANCE_NONE) {
return null;
}
final ClassNodeTracker cnt = enhancer.getPCBytecode();
return AsmHelper.toByteArray(cnt);
} catch (final IOException e) {
throw new IllegalStateException(e);
} finally {
thread.setContextClassLoader(old);
}

View File

@ -18,7 +18,6 @@
*/
package org.apache.openjpa.enhance;
import java.io.ByteArrayInputStream;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.AccessController;
@ -34,11 +33,11 @@ import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.util.GeneralException;
import org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import org.apache.openjpa.util.asm.EnhancementProject;
import org.apache.xbean.asm9.ClassReader;
import org.apache.xbean.asm9.ClassVisitor;
import org.apache.xbean.asm9.Opcodes;
import serp.bytecode.Project;
import static java.util.Arrays.asList;
@ -149,9 +148,9 @@ public class PCClassFileTransformer
ClassLoader oldLoader = AccessController.doPrivileged(J2DoPrivHelper.getContextClassLoaderAction());
AccessController.doPrivileged(J2DoPrivHelper.setContextClassLoaderAction(_tmpLoader));
try {
PCEnhancer enhancer = new PCEnhancer(_repos.getConfiguration(),
new Project().loadClass(new ByteArrayInputStream(bytes),
_tmpLoader), _repos);
EnhancementProject project = new EnhancementProject();
final ClassNodeTracker bc = project.loadClass(bytes, _tmpLoader);
PCEnhancer enhancer = new PCEnhancer(_repos.getConfiguration(), bc, _repos);
enhancer.setAddDefaultConstructor(_flags.addDefaultConstructor);
enhancer.setEnforcePropertyRestrictions
(_flags.enforcePropertyRestrictions);

View File

@ -100,14 +100,13 @@ 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.EnhancementProject;
import org.apache.openjpa.util.asm.RedefinedAttribute;
import org.apache.xbean.asm9.Attribute;
import org.apache.xbean.asm9.Opcodes;
import org.apache.xbean.asm9.Type;
import org.apache.xbean.asm9.tree.*;
import serp.bytecode.BCClass;
import serp.bytecode.Project;
/**
* Bytecode enhancer used to enhance persistent classes from metadata. The
@ -193,12 +192,15 @@ public class PCEnhancer {
}
}
private BCClass _pc;
private final BCClass _managedType;
private final MetaDataRepository _repos;
private final ClassMetaData _meta;
private final Log _log;
boolean _addVersionInitFlag = true;
private final EnhancementProject project;
/**
* represents the managed type.
*/
@ -211,8 +213,6 @@ public class PCEnhancer {
*/
private ClassNodeTracker pc;
private final ClassMetaData _meta;
private final Log _log;
private boolean _defCons = true;
private boolean _redefine = false;
private boolean _subclass = false;
@ -235,8 +235,7 @@ public class PCEnhancer {
* repository.
*/
public PCEnhancer(OpenJPAConfiguration conf, Class<?> type) {
this(conf, AccessController.doPrivileged(SerpPrivacyHelper.loadProjectClassAction(new Project(), type)),
(MetaDataRepository) null);
this(conf, new EnhancementProject().loadClass(type), (MetaDataRepository) null);
}
/**
@ -245,8 +244,7 @@ public class PCEnhancer {
* and then loading from <code>conf</code>'s repository.
*/
public PCEnhancer(OpenJPAConfiguration conf, ClassMetaData meta) {
this(conf, AccessController.doPrivileged(SerpPrivacyHelper.loadProjectClassAction(new Project(), meta.getDescribedType())),
meta.getRepository());
this(conf, new EnhancementProject().loadClass(meta.getDescribedType()), meta.getRepository());
}
/**
@ -260,12 +258,11 @@ public class PCEnhancer {
* because the configuration might be an
* implementation-specific subclass whose metadata
* required more than just base metadata files
* @deprecated use {@link #PCEnhancer(OpenJPAConfiguration, BCClass,
* @deprecated use {@link #PCEnhancer(OpenJPAConfiguration, ClassNodeTracker,
* MetaDataRepository, ClassLoader)} instead.
*/
@Deprecated
public PCEnhancer(OpenJPAConfiguration conf, BCClass type,
MetaDataRepository repos) {
public PCEnhancer(OpenJPAConfiguration conf, ClassNodeTracker type, MetaDataRepository repos) {
this(conf, type, repos, null);
}
@ -283,12 +280,11 @@ 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) {
_managedType = type;
_pc = type;
public PCEnhancer(OpenJPAConfiguration conf, ClassNodeTracker type, MetaDataRepository repos, ClassLoader loader) {
// we assume that the original class and the enhanced class is the same
managedType = AsmHelper.toClassNode(type);
project = type.getProject();
managedType = type;
pc = managedType;
_log = conf.getLog(OpenJPAConfiguration.LOG_ENHANCE);
@ -323,12 +319,10 @@ public class PCEnhancer {
* @param meta the metadata to use for processing this type.
* @since 1.1.0
*/
public PCEnhancer(MetaDataRepository repos, BCClass type, ClassMetaData meta) {
_managedType = type;
_pc = type;
public PCEnhancer(MetaDataRepository repos, ClassNodeTracker type, ClassMetaData meta) {
// we assume that the original class and the enhanced class is the same
managedType = AsmHelper.toClassNode(type);
project = type.getProject();
managedType = type;
pc = managedType;
_log = repos.getConfiguration()
@ -597,7 +591,6 @@ public class PCEnhancer {
addCloningCode();
runAuxiliaryEnhancers();
AsmHelper.readIntoBCClass(pc, _pc);
return ENHANCE_PC;
}
return ENHANCE_AWARE;
@ -631,19 +624,19 @@ public class PCEnhancer {
if (getCreateSubclass()) {
PCSubclassValidator val = new PCSubclassValidator(_meta, managedType.getClassNode(), _log, _fail);
val.assertCanSubclass();
pc = AsmHelper.copyClassNode(managedType, toPCSubclassName(managedType));
_pc = _managedType.getProject().loadClass(toPCSubclassName(managedType));
_pc.setMajorVersion(_managedType.getMajorVersion());
_pc.setMinorVersion(_managedType.getMinorVersion());
if (_pc.getSuperclassBC() != _managedType) {
_pc.setSuperclass(_managedType);
_pc.setAbstract(_managedType.isAbstract());
_pc.declareInterface(DynamicPersistenceCapable.class);
pc = project.loadClass(toPCSubclassName(managedType));
if (pc.getClassNode().superName.equals("java/lang/Object")) {
// set the parent class
pc.getClassNode().superName = managedType.getClassNode().name;
if ((managedType.getClassNode().access & Opcodes.ACC_ABSTRACT) > 0) {
pc.getClassNode().access |= Opcodes.ACC_ABSTRACT;
}
pc.declareInterface(DynamicPersistenceCapable.class);
}
else {
_isAlreadySubclassed = true;
}
pc = AsmHelper.toClassNode(_pc);
}
_bcsConfigured = true;
@ -1408,7 +1401,7 @@ public class PCEnhancer {
classNode.methods.add(newInstance);
final InsnList instructions = newInstance.instructions;
if (_pc.isAbstract()) {
if ((pc.getClassNode().access & Opcodes.ACC_ABSTRACT) > 0) {
instructions.add(throwException(USEREXCEP));
return;
}
@ -3317,7 +3310,7 @@ public class PCEnhancer {
accessMode = Opcodes.ACC_PUBLIC;
access = "public";
}
else if (_pc.isFinal()) {
else if ((pc.getClassNode().access & Opcodes.ACC_FINAL) > 0) {
accessMode = Opcodes.ACC_PRIVATE;
access = "private";
}
@ -3461,7 +3454,7 @@ public class PCEnhancer {
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
}
if (_pc.isAbstract()) {
if ((pc.getClassNode().access & Opcodes.ACC_ABSTRACT) > 0) {
instructions.add(new InsnNode(Opcodes.ACONST_NULL));
}
else {
@ -4716,7 +4709,7 @@ public class PCEnhancer {
// declare externalizable interface
if (!Externalizable.class.isAssignableFrom(_meta.getDescribedType())) {
pc.getClassNode().interfaces.add(Type.getInternalName(Externalizable.class));
pc.declareInterface(Externalizable.class);
}
// make sure the user doesn't already have custom externalization or
@ -5602,8 +5595,8 @@ public class PCEnhancer {
}
}
Project project = new Project();
BCClass bc;
EnhancementProject project = new EnhancementProject();
ClassNodeTracker cnt;
PCEnhancer enhancer;
Collection persAwareClasses = new HashSet();
@ -5614,12 +5607,12 @@ public class PCEnhancer {
}
if (o instanceof String) {
bc = project.loadClass((String) o, loader);
cnt = project.loadClass((String) o, loader);
}
else {
bc = project.loadClass((Class) o);
cnt = project.loadClass((Class) o);
}
enhancer = new PCEnhancer(conf, bc, repos, loader);
enhancer = new PCEnhancer(conf, cnt, repos, loader);
if (writer != null) {
enhancer.setBytecodeWriter(writer);
}

View File

@ -248,10 +248,10 @@ public class PCRegistry {
* Look up the metadata for a <code>PersistenceCapable</code> class.
*/
private static Meta getMeta(Class<?> pcClass) {
Meta ret = (Meta) _metas.get(pcClass);
if (ret == null)
throw new IllegalStateException(_loc.get("no-meta", pcClass).
getMessage());
Meta ret = _metas.get(pcClass);
if (ret == null) {
throw new IllegalStateException(_loc.get("no-meta", pcClass).getMessage());
}
return ret;
}

View File

@ -18,7 +18,6 @@
*/
package org.apache.openjpa.meta;
import java.io.ByteArrayInputStream;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
@ -28,14 +27,17 @@ 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;
import org.apache.openjpa.util.InternalException;
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.Type;
import serp.bytecode.BCClass;
import serp.bytecode.BCClassLoader;
import serp.bytecode.BCField;
import serp.bytecode.BCMethod;
import serp.bytecode.Code;
@ -49,16 +51,13 @@ import serp.bytecode.Project;
* @author Steve Kim
*/
class InterfaceImplGenerator {
private static final Localizer _loc = Localizer.forPackage
(InterfaceImplGenerator.class);
private static final Localizer _loc = Localizer.forPackage(InterfaceImplGenerator.class);
private static final String POSTFIX = "openjpaimpl";
private final MetaDataRepository _repos;
private final Map<Class<?>,Class<?>> _impls = new WeakHashMap<>();
private final Project _project = new Project();
private final EnhancementProject _project = new EnhancementProject();
// distinct project / loader for enhanced version of class
private final Project _enhProject = new Project();
/**
* Constructor. Supply repository.
@ -79,45 +78,46 @@ class InterfaceImplGenerator {
if (impl != null)
return impl;
// distinct temp project / loader for enhancing
EnhancementProject _enhProject = new EnhancementProject();
ClassLoader parentLoader = AccessController.doPrivileged(
J2DoPrivHelper.getClassLoaderAction(iface));
BCClassLoader loader = AccessController
.doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(_project,
parentLoader));
BCClassLoader enhLoader = AccessController
.doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(_enhProject,
parentLoader));
BCClass bc = _project.loadClass(getClassName(meta));
EnhancementClassLoader loader = new EnhancementClassLoader(_project, parentLoader);
EnhancementClassLoader enhLoader = new EnhancementClassLoader(_enhProject, parentLoader);
ClassNodeTracker bc = _project.loadClass(getClassName(meta), loader);
bc.declareInterface(iface);
ClassMetaData sup = meta.getPCSuperclassMetaData();
if (sup != null) {
bc.setSuperclass(sup.getInterfaceImpl());
enhLoader = AccessController
.doPrivileged(SerpPrivacyHelper.newBCClassLoaderAction(
_enhProject, AccessController
.doPrivileged(J2DoPrivHelper.getClassLoaderAction(sup
.getInterfaceImpl()))));
bc.getClassNode().superName = Type.getInternalName(sup.getInterfaceImpl());
//X 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.getName(), true, loader));
} catch (Throwable t) {
throw new InternalException(_loc.get("interface-load", iface,
loader), t).setFatal(true);
}
// copy the BCClass<?> into the enhancer project.
bc = _enhProject.loadClass(new ByteArrayInputStream(bc.toByteArray()),
loader);
PCEnhancer enhancer = new PCEnhancer(_repos, bc, meta);
//X bc = _enhProject.loadClass(new ByteArrayInputStream(_bc.toByteArray()), loader);
ClassNodeTracker bcEnh = AsmHelper.toClassNode(_enhProject, _bc);
PCEnhancer enhancer = new PCEnhancer(_repos, bcEnh, meta);
int result = enhancer.run();
if (result != PCEnhancer.ENHANCE_PC)
@ -128,8 +128,8 @@ class InterfaceImplGenerator {
String pcClassName = enhancer.getPCBytecode().getClassNode().name.replace("/", ".");
impl = Class.forName(pcClassName, true, enhLoader);
} catch (Throwable t) {
throw new InternalException(_loc.get("interface-load2", iface,
enhLoader), t).setFatal(true);
//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);
}
// cache the generated impl.
_impls.put(iface, impl);

View File

@ -50,7 +50,7 @@ import serp.bytecode.Project;
*/
public final class AsmHelper {
private static final char[] PRIMITIVE_DESCRIPTORS = {'V','Z','C','B','S','I','F','J','D'};
private static final Attribute[] ATTRS = new Attribute[] {
public static final Attribute[] ATTRS = new Attribute[] {
new RedefinedAttribute()
};
@ -79,40 +79,20 @@ public final class AsmHelper {
}
}
/**
* Copy the binary information from the ClassNodeTracker to a new one
* @param cntIn the original ASM class representation
* @param newClassName the class name of the new ClassNodeTracker
* @return a new ClassNodeTracker
*/
public static ClassNodeTracker copyClassNode(ClassNodeTracker cntIn, String newClassName) {
final byte[] classBytes = toByteArray(cntIn);
ClassReader cr = new ClassReader(classBytes);
ClassNode classNode = new ClassNode(Opcodes.ASM9);
cr.accept(classNode, ATTRS, 0);
if ((classNode.version & 0xffff) < 49) {
classNode.version = 49;
}
return new ClassNodeTracker(classNode, cntIn.getClassLoader());
}
/**
* Read the binary bytecode from the class with the given name
* @param classLoader the ClassLoader to use
* @param className the fully qualified class name to read. e.g. "org.mycorp.mypackage.MyEntity"
* @return the ClassNode constructed from that class
*/
public static ClassNode readClassNode(ClassLoader classLoader, String className) {
public static ClassNode readClassNode(ClassLoader classLoader, String className) throws ClassNotFoundException {
ClassReader cr;
final String classResourceName = className.replace(".", "/") + ".class";
try (final InputStream classBytesStream = classLoader.getResourceAsStream(classResourceName)) {
cr = new ClassReader(classBytesStream);
}
catch (IOException e) {
throw new RuntimeException(e);
throw new ClassNotFoundException("Cannot read ClassNode for class " + className, e);
}
ClassNode classNode = new ClassNode();
cr.accept(classNode, ATTRS, 0);
@ -184,7 +164,7 @@ public final class AsmHelper {
* 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) {
public static ClassNodeTracker toClassNode(EnhancementProject project, BCClass bcClass) {
ClassReader cr = new ClassReader(bcClass.toByteArray());
ClassNode classNode = new ClassNode(Opcodes.ASM9);
cr.accept(classNode, ATTRS, 0);
@ -193,7 +173,8 @@ public final class AsmHelper {
classNode.version = 49;
}
return new ClassNodeTracker(classNode, bcClass.getClassLoader());
final ClassNodeTracker cnt = new ClassNodeTracker(project, classNode, bcClass.getClassLoader());
return cnt;
}
/**

View File

@ -16,6 +16,9 @@
*/
package org.apache.openjpa.util.asm;
import java.util.ArrayList;
import org.apache.xbean.asm9.Type;
import org.apache.xbean.asm9.tree.ClassNode;
/**
@ -26,11 +29,32 @@ import org.apache.xbean.asm9.tree.ClassNode;
public class ClassNodeTracker {
private final ClassNode classNode;
private final ClassLoader cl;
private final EnhancementProject project;
public ClassNodeTracker(ClassNode classNode, ClassLoader cl) {
public ClassNodeTracker(EnhancementProject project, ClassNode classNode, ClassLoader cl) {
this.project = project;
this.classNode = classNode;
if (hasEnhancementCl(cl)) {
this.cl = cl;
}
else {
this.cl = new EnhancementClassLoader(project, cl);
}
project.putClass(classNode.name.replace("/", "."), this);
}
private boolean hasEnhancementCl(ClassLoader cl) {
boolean hasEhCl = false;
do {
if (cl instanceof EnhancementClassLoader) {
hasEhCl = true;
break;
}
cl = cl.getParent();
} while (cl != null);
return hasEhCl;
}
public ClassNode getClassNode() {
return classNode;
@ -40,6 +64,10 @@ public class ClassNodeTracker {
return cl;
}
public EnhancementProject getProject() {
return project;
}
public Class<?> getType() {
try {
return Class.forName(classNode.name.replace("/", "."), false, cl);
@ -48,4 +76,11 @@ public class ClassNodeTracker {
throw new RuntimeException(e);
}
}
public void declareInterface(Class<?> iface) {
if (classNode.interfaces == null) {
classNode.interfaces = new ArrayList<>();
}
classNode.interfaces.add(Type.getInternalName(iface));
}
}

View File

@ -32,7 +32,7 @@ public class EnhancementClassLoader extends ClassLoader {
this.project = project;
}
public EnhancementClassLoader(ClassLoader parent, EnhancementProject project) {
public EnhancementClassLoader(EnhancementProject project, ClassLoader parent) {
super(parent);
this.project = project;
}
@ -41,6 +41,15 @@ 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;

View File

@ -18,8 +18,9 @@ package org.apache.openjpa.util.asm;
import java.util.HashMap;
import org.apache.openjpa.util.asm.AsmHelper;
import org.apache.openjpa.util.asm.ClassNodeTracker;
import org.apache.openjpa.lib.util.JavaVersions;
import org.apache.xbean.asm9.ClassReader;
import org.apache.xbean.asm9.Opcodes;
import org.apache.xbean.asm9.tree.ClassNode;
@ -30,26 +31,36 @@ import org.apache.xbean.asm9.tree.ClassNode;
*/
public class EnhancementProject {
private HashMap<String, ClassNodeTracker> classNodTrackers = new HashMap<>();
private HashMap<String, ClassNodeTracker> classNodeTrackers = new HashMap<>();
/**
* Return true if the project already contains the given class.
*/
public boolean containsClass(String type) {
return classNodTrackers.containsKey(type);
return classNodeTrackers.containsKey(type);
}
/**
* Load a class with the given name.
*
* @param name the fully qualified class name
* @see #loadClass(String,ClassLoader)
*/
public ClassNodeTracker loadClass(String name) {
return loadClass(name, null);
}
/**
* Load a class with the given type.
*
* @see #loadClass(String,ClassLoader)
*/
public ClassNodeTracker loadClass(Class<?> type) {
return loadClass(type.getName(), type.getClassLoader());
}
/**
* Load the bytecode for the class with the given name.
* If a {@link ClassNodeTracker} with the given name already exists in this project,
@ -66,7 +77,7 @@ public class EnhancementProject {
* @throws RuntimeException on parse error
*/
public ClassNodeTracker loadClass(String name, ClassLoader loader) {
ClassNodeTracker cached = classNodTrackers.get(name);
ClassNodeTracker cached = classNodeTrackers.get(name);
if (cached != null) {
return cached;
}
@ -76,10 +87,54 @@ public class EnhancementProject {
loader = Thread.currentThread().getContextClassLoader();
}
final ClassNode classNode = AsmHelper.readClassNode(loader, name);
ClassNodeTracker cnt = new ClassNodeTracker(classNode, loader);
classNodTrackers.put(name, cnt);
ClassNode classNode;
try {
classNode = AsmHelper.readClassNode(loader, name);
}
catch (ClassNotFoundException e) {
// otherwise create a new ClassNode
classNode = new ClassNode(Opcodes.ASM9);
classNode.version = detectJavaBytecodeVersion();
classNode.name = name.replace(".", "/");
classNode.access = Opcodes.ACC_PUBLIC;
classNode.superName = "java/lang/Object";
}
ClassNodeTracker cnt = new ClassNodeTracker(this, classNode, loader);
return cnt;
}
/**
* 49 Java 1.5
* 50 Java 1.6
* 51 Java 1.7
* 52 Java 1.8
* 53 Java9
* 54 Java10
* 55 Java11
* etc
*
* @return the bytecode version of the current VM
*/
private int detectJavaBytecodeVersion() {
return JavaVersions.VERSION + 44;
}
public ClassNodeTracker loadClass(byte[] bytes, ClassLoader loader) {
ClassReader cr = new ClassReader(bytes);
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;
}
public void clear() {
classNodeTrackers.clear();
}
void putClass(String name, ClassNodeTracker cnt) {
classNodeTrackers.put(name, cnt);
}
}

View File

@ -58,7 +58,15 @@ public class JavaVersions {
else if ("1.8".equals(specVersion))
VERSION = 8;
else {
VERSION = Integer.parseInt(specVersion);
int v;
try {
v = Integer.parseInt(specVersion);
}
catch (NumberFormatException nfe) {
// default to Java 8
v = 8;
}
VERSION = v;
}
}

View File

@ -21,7 +21,6 @@ package org.apache.openjpa.enhance;
import java.io.IOException;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.openjpa.conf.OpenJPAConfiguration;
@ -33,26 +32,24 @@ 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.openjpa.util.asm.EnhancementProject;
import org.apache.xbean.asm9.Type;
import serp.bytecode.BCClass;
import serp.bytecode.Project;
public class TestEnhancementWithMultiplePUs
extends AbstractCachedEMFTestCase {
public void testExplicitEnhancementWithClassNotInFirstPU()
throws ClassNotFoundException {
public void testExplicitEnhancementWithClassNotInFirstPU() throws ClassNotFoundException {
OpenJPAConfiguration conf = new OpenJPAConfigurationImpl();
Configurations.populateConfiguration(conf, new Options());
MetaDataRepository repos = conf.getMetaDataRepositoryInstance();
ClassLoader loader = AccessController
.doPrivileged(J2DoPrivHelper.newTemporaryClassLoaderAction(
getClass().getClassLoader()));
Project project = new Project();
EnhancementProject project = new EnhancementProject();
String className = "org.apache.openjpa.enhance.UnenhancedBootstrapInstance";
BCClass bc = assertNotPC(loader, project, className);
ClassNodeTracker bc = assertNotPC(loader, project, className);
PCEnhancer enhancer = new PCEnhancer(conf, bc, repos, loader);
@ -61,11 +58,10 @@ public class TestEnhancementWithMultiplePUs
assertTrue(enhancer.getPCBytecode().getClassNode().interfaces.contains(Type.getInternalName(PersistenceCapable.class)));
}
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(
PersistenceCapable.class.getName()));
private ClassNodeTracker assertNotPC(ClassLoader loader, EnhancementProject project, String className) {
ClassNodeTracker bc = project.loadClass(className, loader);
assertTrue(className + " must not be enhanced already; it was.",
bc.getClassNode().interfaces == null || !bc.getClassNode().interfaces.contains(Type.getInternalName(PersistenceCapable.class)));
return bc;
}
@ -80,7 +76,7 @@ public class TestEnhancementWithMultiplePUs
ClassLoader loader = AccessController
.doPrivileged(J2DoPrivHelper.newTemporaryClassLoaderAction(
getClass().getClassLoader()));
Project project = new Project();
EnhancementProject project = new EnhancementProject();
// make sure that the class is not already enhanced for some reason
String className = "org/apache/openjpa/enhance/UnenhancedBootstrapInstance";
@ -118,7 +114,7 @@ public class TestEnhancementWithMultiplePUs
ClassLoader loader = AccessController
.doPrivileged(J2DoPrivHelper.newTemporaryClassLoaderAction(
getClass().getClassLoader()));
Project project = new Project();
EnhancementProject project = new EnhancementProject();
// make sure that the classes is not already enhanced for some reason
assertNotPC(loader, project,