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 0a81c3de7 OPENJPA-2911 move PCEnhancer off Serp
0a81c3de7 is described below
commit 0a81c3de7b8c590bf54b9d4138c51744684d369a
Author: Mark Struberg <[email protected]>
AuthorDate: Wed Jul 19 13:14:16 2023 +0200
OPENJPA-2911 move PCEnhancer off Serp
---
.../internal/OpenJPADirectoriesEnhancer.java | 7 +-
.../openjpa/enhance/PCClassFileTransformer.java | 9 ++-
.../org/apache/openjpa/enhance/PCEnhancer.java | 75 ++++++++++------------
.../org/apache/openjpa/enhance/PCRegistry.java | 8 +--
.../openjpa/meta/InterfaceImplGenerator.java | 58 ++++++++---------
.../org/apache/openjpa/util/asm/AsmHelper.java | 31 ++-------
.../apache/openjpa/util/asm/ClassNodeTracker.java | 39 ++++++++++-
.../openjpa/util/asm/EnhancementClassLoader.java | 11 +++-
.../openjpa/util/asm/EnhancementProject.java | 71 +++++++++++++++++---
.../org/apache/openjpa/lib/util/JavaVersions.java | 10 ++-
.../enhance/TestEnhancementWithMultiplePUs.java | 24 +++----
11 files changed, 209 insertions(+), 134 deletions(-)
diff --git
a/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
b/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
index 6bae9091c..9bb8bea09 100644
---
a/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
+++
b/openjpa-junit5/src/main/java/org/apache/openjpa/junit5/internal/OpenJPADirectoriesEnhancer.java
@@ -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);
}
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java
index f46663f31..ba6c97074 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCClassFileTransformer.java
@@ -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);
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 fb52bc3cc..bc3ef3934 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
@@ -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);
}
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
index 0a79ec12a..4ff6176cd 100644
--- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
+++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCRegistry.java
@@ -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;
}
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 11324f9bc..07fc7ee80 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
@@ -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);
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 529ba4888..0e1b007fe 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
@@ -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;
}
/**
diff --git
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
index 1b08b1a52..acb615d7d 100644
---
a/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
+++
b/openjpa-kernel/src/main/java/org/apache/openjpa/util/asm/ClassNodeTracker.java
@@ -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,10 +29,31 @@ 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;
- this.cl = cl;
+ 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() {
@@ -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));
+ }
}
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 8c971d513..462eabc13 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
@@ -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;
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 451ce039b..de93f1a18 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
@@ -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);
+ }
+
}
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 222770d6e..45c737fe7 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
@@ -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;
}
}
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 38dc3cdfb..c61e0f2cd 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
@@ -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,