mirror of https://github.com/apache/openjpa.git
OPENJPA-2911 move PCEnhancer off Serp
This commit is contained in:
parent
dfaf8da48e
commit
0a81c3de7b
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue