mirror of https://github.com/apache/openjpa.git
OPENJPA-2911 move PCSubclassValidator to ASM
This commit is contained in:
parent
2c3d37e859
commit
3ea2412003
|
@ -97,7 +97,6 @@ import org.apache.openjpa.util.StringId;
|
||||||
import org.apache.openjpa.util.UserException;
|
import org.apache.openjpa.util.UserException;
|
||||||
import org.apache.openjpa.util.asm.AsmHelper;
|
import org.apache.openjpa.util.asm.AsmHelper;
|
||||||
import org.apache.openjpa.util.asm.ClassWriterTracker;
|
import org.apache.openjpa.util.asm.ClassWriterTracker;
|
||||||
import org.apache.xbean.asm9.ClassReader;
|
|
||||||
import org.apache.xbean.asm9.Opcodes;
|
import org.apache.xbean.asm9.Opcodes;
|
||||||
import org.apache.xbean.asm9.Type;
|
import org.apache.xbean.asm9.Type;
|
||||||
import org.apache.xbean.asm9.tree.AbstractInsnNode;
|
import org.apache.xbean.asm9.tree.AbstractInsnNode;
|
||||||
|
@ -225,9 +224,9 @@ public class PCEnhancer {
|
||||||
private Set _violations = null;
|
private Set _violations = null;
|
||||||
private File _dir = null;
|
private File _dir = null;
|
||||||
private BytecodeWriter _writer = null;
|
private BytecodeWriter _writer = null;
|
||||||
private Map _backingFields = null; // map of set / get names => field names
|
private Map<String, String> _backingFields = null; // map of set / get names => field names
|
||||||
private Map _attrsToFields = null; // map of attr names => field names
|
private Map<String, String> _attrsToFields = null; // map of attr names => field names
|
||||||
private Map _fieldsToAttrs = null; // map of field names => attr names
|
private Map<String, String> _fieldsToAttrs = null; // map of field names => attr names
|
||||||
private boolean _isAlreadyRedefined = false;
|
private boolean _isAlreadyRedefined = false;
|
||||||
private boolean _isAlreadySubclassed = false;
|
private boolean _isAlreadySubclassed = false;
|
||||||
private boolean _bcsConfigured = false;
|
private boolean _bcsConfigured = false;
|
||||||
|
@ -573,12 +572,14 @@ public class PCEnhancer {
|
||||||
_log.trace(_loc.get("enhance-start", type));
|
_log.trace(_loc.get("enhance-start", type));
|
||||||
}
|
}
|
||||||
|
|
||||||
configureBCs();
|
final ClassNode classNode = AsmHelper.readClassNode(_managedType.toByteArray());
|
||||||
|
|
||||||
|
configureBCs(classNode);
|
||||||
|
|
||||||
// validate properties before replacing field access so that
|
// validate properties before replacing field access so that
|
||||||
// we build up a record of backing fields, etc
|
// we build up a record of backing fields, etc
|
||||||
if (isPropertyAccess(_meta)) {
|
if (isPropertyAccess(_meta)) {
|
||||||
validateProperties();
|
validateProperties(classNode);
|
||||||
if (getCreateSubclass()) {
|
if (getCreateSubclass()) {
|
||||||
addAttributeTranslation();
|
addAttributeTranslation();
|
||||||
}
|
}
|
||||||
|
@ -607,22 +608,21 @@ public class PCEnhancer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void configureBCs() {
|
private void configureBCs(final ClassNode classNode) {
|
||||||
if (!_bcsConfigured) {
|
if (!_bcsConfigured) {
|
||||||
if (getRedefine()) {
|
if (getRedefine()) {
|
||||||
if (_managedType.getAttribute(REDEFINED_ATTRIBUTE) == null)
|
if (_managedType.getAttribute(REDEFINED_ATTRIBUTE) == null) {
|
||||||
_managedType.addAttribute(REDEFINED_ATTRIBUTE);
|
_managedType.addAttribute(REDEFINED_ATTRIBUTE);
|
||||||
else
|
} else {
|
||||||
_isAlreadyRedefined = true;
|
_isAlreadyRedefined = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getCreateSubclass()) {
|
if (getCreateSubclass()) {
|
||||||
PCSubclassValidator val = new PCSubclassValidator(
|
PCSubclassValidator val = new PCSubclassValidator(_meta, classNode, _managedType, _log, _fail);
|
||||||
_meta, _managedType, _log, _fail);
|
|
||||||
val.assertCanSubclass();
|
val.assertCanSubclass();
|
||||||
|
|
||||||
_pc = _managedType.getProject().loadClass(
|
_pc = _managedType.getProject().loadClass(toPCSubclassName(_managedType.getType()));
|
||||||
toPCSubclassName(_managedType.getType()));
|
|
||||||
if (_pc.getSuperclassBC() != _managedType) {
|
if (_pc.getSuperclassBC() != _managedType) {
|
||||||
_pc.setSuperclass(_managedType);
|
_pc.setSuperclass(_managedType);
|
||||||
_pc.setAbstract(_managedType.isAbstract());
|
_pc.setAbstract(_managedType.isAbstract());
|
||||||
|
@ -699,12 +699,14 @@ public class PCEnhancer {
|
||||||
* written correctly. This method also gathers information on each
|
* written correctly. This method also gathers information on each
|
||||||
* property's backing field.
|
* property's backing field.
|
||||||
*/
|
*/
|
||||||
private void validateProperties() {
|
private void validateProperties(ClassNode classNode) {
|
||||||
FieldMetaData[] fmds;
|
FieldMetaData[] fmds;
|
||||||
if (getCreateSubclass())
|
if (getCreateSubclass()) {
|
||||||
fmds = _meta.getFields();
|
fmds = _meta.getFields();
|
||||||
else
|
}
|
||||||
|
else {
|
||||||
fmds = _meta.getDeclaredFields();
|
fmds = _meta.getDeclaredFields();
|
||||||
|
}
|
||||||
Method meth;
|
Method meth;
|
||||||
|
|
||||||
BCMethod bcGetter, bcSetter;
|
BCMethod bcGetter, bcSetter;
|
||||||
|
@ -728,6 +730,7 @@ public class PCEnhancer {
|
||||||
}
|
}
|
||||||
|
|
||||||
meth = (Method) fmd.getBackingMember();
|
meth = (Method) fmd.getBackingMember();
|
||||||
|
|
||||||
// ##### this will fail if we override and don't call super.
|
// ##### this will fail if we override and don't call super.
|
||||||
BCClass declaringType = _managedType.getProject()
|
BCClass declaringType = _managedType.getProject()
|
||||||
.loadClass(fmd.getDeclaringType());
|
.loadClass(fmd.getDeclaringType());
|
||||||
|
@ -739,12 +742,13 @@ public class PCEnhancer {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
bcReturned = getReturnedField_old(bcGetter);
|
bcReturned = getReturnedField_old(bcGetter);
|
||||||
returned = getReturnedField(meth);
|
getter = meth;
|
||||||
|
returned = getReturnedField(classNode, getter);
|
||||||
|
|
||||||
//X TODO remove
|
//X TODO remove
|
||||||
PCEnhancer.assertSameField(returned, bcReturned);
|
PCEnhancer.assertSameField(returned, bcReturned);
|
||||||
|
|
||||||
if (bcReturned != null) {
|
if (returned != null) {
|
||||||
registerBackingFieldInfo(fmd, bcGetter, bcReturned);
|
registerBackingFieldInfo(fmd, bcGetter, bcReturned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -774,7 +778,7 @@ public class PCEnhancer {
|
||||||
if (bcSetter != null) {
|
if (bcSetter != null) {
|
||||||
bcAssigned = getAssignedField_old(bcSetter);
|
bcAssigned = getAssignedField_old(bcSetter);
|
||||||
|
|
||||||
assigned = getAssignedField(getMethod(fmd.getDeclaringType(), fmd.getSetterName(), new Class[]{fmd.getDeclaredType()}));
|
assigned = getAssignedField(classNode, getMethod(fmd.getDeclaringType(), fmd.getSetterName(), new Class[]{fmd.getDeclaredType()}));
|
||||||
assertSameField(assigned, bcAssigned);
|
assertSameField(assigned, bcAssigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,18 +794,20 @@ public class PCEnhancer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerBackingFieldInfo(FieldMetaData fmd, BCMethod method,
|
private void registerBackingFieldInfo(FieldMetaData fmd, BCMethod method, BCField field) {
|
||||||
BCField field) {
|
if (_backingFields == null) {
|
||||||
if (_backingFields == null)
|
|
||||||
_backingFields = new HashMap();
|
_backingFields = new HashMap();
|
||||||
|
}
|
||||||
_backingFields.put(method.getName(), field.getName());
|
_backingFields.put(method.getName(), field.getName());
|
||||||
|
|
||||||
if (_attrsToFields == null)
|
if (_attrsToFields == null) {
|
||||||
_attrsToFields = new HashMap();
|
_attrsToFields = new HashMap();
|
||||||
|
}
|
||||||
_attrsToFields.put(fmd.getName(), field.getName());
|
_attrsToFields.put(fmd.getName(), field.getName());
|
||||||
|
|
||||||
if (_fieldsToAttrs == null)
|
if (_fieldsToAttrs == null) {
|
||||||
_fieldsToAttrs = new HashMap();
|
_fieldsToAttrs = new HashMap();
|
||||||
|
}
|
||||||
_fieldsToAttrs.put(field.getName(), fmd.getName());
|
_fieldsToAttrs.put(field.getName(), fmd.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,13 +892,14 @@ public class PCEnhancer {
|
||||||
* Return the field returned by the given method, or null if none.
|
* Return the field returned by the given method, or null if none.
|
||||||
* Package-protected and static for testing.
|
* Package-protected and static for testing.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
static BCField getReturnedField_old(BCMethod meth) {
|
static BCField getReturnedField_old(BCMethod meth) {
|
||||||
return findField_old(meth, new Code().xreturn()
|
return findField_old(meth, new Code().xreturn()
|
||||||
.setType(meth.getReturnType()), false);
|
.setType(meth.getReturnType()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Field getReturnedField(Method meth) {
|
static Field getReturnedField(ClassNode classNode, Method meth) {
|
||||||
return findField(meth, (ain) -> ain.getOpcode() == AsmHelper.getReturnInsn(meth.getReturnType()), false);
|
return findField(classNode, meth, (ain) -> ain.getOpcode() == AsmHelper.getReturnInsn(meth.getReturnType()), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -900,13 +907,14 @@ public class PCEnhancer {
|
||||||
* Return the field assigned in the given method, or null if none.
|
* Return the field assigned in the given method, or null if none.
|
||||||
* Package-protected and static for testing.
|
* Package-protected and static for testing.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
static BCField getAssignedField_old(BCMethod meth) {
|
static BCField getAssignedField_old(BCMethod meth) {
|
||||||
return findField_old(meth, (AccessController.doPrivileged(
|
return findField_old(meth, (AccessController.doPrivileged(
|
||||||
J2DoPrivHelper.newCodeAction())).putfield(), true);
|
J2DoPrivHelper.newCodeAction())).putfield(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Field getAssignedField(Method meth) {
|
static Field getAssignedField(ClassNode classNode, Method meth) {
|
||||||
return findField(meth, (ain) -> ain.getOpcode() == Opcodes.PUTFIELD, true);
|
return findField(classNode, meth, (ain) -> ain.getOpcode() == Opcodes.PUTFIELD, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -914,6 +922,7 @@ public class PCEnhancer {
|
||||||
* null if non-fields (methods, literals, parameters, variables) are
|
* null if non-fields (methods, literals, parameters, variables) are
|
||||||
* returned, or if non-parameters are assigned to fields.
|
* returned, or if non-parameters are assigned to fields.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
private static BCField findField_old(BCMethod meth, Instruction template, boolean findAccessed) {
|
private static BCField findField_old(BCMethod meth, Instruction template, boolean findAccessed) {
|
||||||
// ignore any static methods. OpenJPA only currently supports
|
// ignore any static methods. OpenJPA only currently supports
|
||||||
// non-static setters and getters
|
// non-static setters and getters
|
||||||
|
@ -980,24 +989,17 @@ public class PCEnhancer {
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Field findField(ClassNode classNode, Method meth, Predicate<AbstractInsnNode> ain, boolean findAccessed) {
|
||||||
private static Field findField(Method meth, Predicate<AbstractInsnNode> ain, boolean findAccessed) {
|
|
||||||
// ignore any static methods. OpenJPA only currently supports
|
// ignore any static methods. OpenJPA only currently supports
|
||||||
// non-static setters and getters
|
// non-static setters and getters
|
||||||
if (Modifier.isStatic(meth.getModifiers())) {
|
if (Modifier.isStatic(meth.getModifiers())) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClassReader cr;
|
if (meth.getDeclaringClass().isInterface()) {
|
||||||
final String classResourceName = meth.getDeclaringClass().getName().replace(".", "/") + ".class";
|
return null;
|
||||||
try (final InputStream classBytesStream = meth.getDeclaringClass().getClassLoader().getResourceAsStream(classResourceName)) {
|
|
||||||
cr = new ClassReader(classBytesStream);
|
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
ClassNode classNode = new ClassNode();
|
|
||||||
cr.accept(classNode, 0);
|
|
||||||
final MethodNode methodNode = classNode.methods.stream()
|
final MethodNode methodNode = classNode.methods.stream()
|
||||||
.filter(mn -> mn.name.equals(meth.getName()) && mn.desc.equals(Type.getMethodDescriptor(meth)))
|
.filter(mn -> mn.name.equals(meth.getName()) && mn.desc.equals(Type.getMethodDescriptor(meth)))
|
||||||
.findAny().get();
|
.findAny().get();
|
||||||
|
@ -3437,7 +3439,7 @@ public class PCEnhancer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a custom readObject method that delegates to the
|
* Adds a custom readObject method that delegates to the
|
||||||
* {@link ObjectInputStream#readObject} method.
|
* {@link ObjectInputStream#readObject()} method.
|
||||||
*/
|
*/
|
||||||
private void modifyReadObjectMethod(BCMethod method, boolean full) {
|
private void modifyReadObjectMethod(BCMethod method, boolean full) {
|
||||||
Code code = method.getCode(true);
|
Code code = method.getCode(true);
|
||||||
|
@ -4935,7 +4937,7 @@ public class PCEnhancer {
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li><i>-properties/-p <properties file></i>: The path to a OpenJPA
|
* <li><i>-properties/-p <properties file></i>: The path to a OpenJPA
|
||||||
* properties file containing information as outlined in
|
* properties file containing information as outlined in
|
||||||
* {@link Configuration}; optional.</li>
|
* {@link org.apache.openjpa.lib.conf.Configuration}; optional.</li>
|
||||||
* <li><i>-<property name> <property value></i>: All bean
|
* <li><i>-<property name> <property value></i>: All bean
|
||||||
* properties of the standard OpenJPA {@link OpenJPAConfiguration} can be
|
* properties of the standard OpenJPA {@link OpenJPAConfiguration} can be
|
||||||
* set by using their names and supplying a value; for example:
|
* set by using their names and supplying a value; for example:
|
||||||
|
|
|
@ -27,6 +27,7 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import org.apache.openjpa.lib.log.Log;
|
import org.apache.openjpa.lib.log.Log;
|
||||||
import org.apache.openjpa.lib.util.Localizer;
|
import org.apache.openjpa.lib.util.Localizer;
|
||||||
|
@ -36,6 +37,7 @@ import org.apache.openjpa.meta.AccessCode;
|
||||||
import org.apache.openjpa.meta.ClassMetaData;
|
import org.apache.openjpa.meta.ClassMetaData;
|
||||||
import org.apache.openjpa.meta.FieldMetaData;
|
import org.apache.openjpa.meta.FieldMetaData;
|
||||||
import org.apache.openjpa.util.UserException;
|
import org.apache.openjpa.util.UserException;
|
||||||
|
import org.apache.xbean.asm9.tree.ClassNode;
|
||||||
|
|
||||||
import serp.bytecode.BCClass;
|
import serp.bytecode.BCClass;
|
||||||
import serp.bytecode.BCField;
|
import serp.bytecode.BCField;
|
||||||
|
@ -83,6 +85,7 @@ public class PCSubclassValidator {
|
||||||
Localizer.forPackage(PCSubclassValidator.class);
|
Localizer.forPackage(PCSubclassValidator.class);
|
||||||
|
|
||||||
private final ClassMetaData meta;
|
private final ClassMetaData meta;
|
||||||
|
private final ClassNode classNode;
|
||||||
private final BCClass bc;
|
private final BCClass bc;
|
||||||
private final Log log;
|
private final Log log;
|
||||||
private final boolean failOnContractViolations;
|
private final boolean failOnContractViolations;
|
||||||
|
@ -90,9 +93,10 @@ public class PCSubclassValidator {
|
||||||
private Collection errors;
|
private Collection errors;
|
||||||
private Collection contractViolations;
|
private Collection contractViolations;
|
||||||
|
|
||||||
public PCSubclassValidator(ClassMetaData meta, BCClass bc, Log log,
|
public PCSubclassValidator(ClassMetaData meta, ClassNode classNode, BCClass bc, Log log,
|
||||||
boolean enforceContractViolations) {
|
boolean enforceContractViolations) {
|
||||||
this.meta = meta;
|
this.meta = meta;
|
||||||
|
this.classNode = classNode;
|
||||||
this.bc = bc;
|
this.bc = bc;
|
||||||
this.log = log;
|
this.log = log;
|
||||||
this.failOnContractViolations = enforceContractViolations;
|
this.failOnContractViolations = enforceContractViolations;
|
||||||
|
@ -148,7 +152,7 @@ public class PCSubclassValidator {
|
||||||
fmd.getName()), fmd);
|
fmd.getName()), fmd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BCField returnedField = checkGetterIsSubclassable(getter, fmd);
|
Field returnedField = checkGetterIsSubclassable(getter, fmd);
|
||||||
|
|
||||||
Method setter = setterForField(fmd);
|
Method setter = setterForField(fmd);
|
||||||
if (setter == null) {
|
if (setter == null) {
|
||||||
|
@ -156,12 +160,12 @@ public class PCSubclassValidator {
|
||||||
fmd);
|
fmd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BCField assignedField = checkSetterIsSubclassable(setter, fmd);
|
Field assignedField = checkSetterIsSubclassable(setter, fmd);
|
||||||
if (assignedField == null) {
|
if (assignedField == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (assignedField != returnedField) {
|
if (!Objects.equals(assignedField, returnedField)) {
|
||||||
addContractViolation(loc.get("subclasser-setter-getter-field-mismatch",
|
addContractViolation(loc.get("subclasser-setter-getter-field-mismatch",
|
||||||
fmd.getName(), returnedField, assignedField),
|
fmd.getName(), returnedField, assignedField),
|
||||||
fmd);
|
fmd);
|
||||||
|
@ -199,20 +203,20 @@ public class PCSubclassValidator {
|
||||||
* <code>null</code> if something other than a single field is
|
* <code>null</code> if something other than a single field is
|
||||||
* returned, or if it cannot be determined what is returned.
|
* returned, or if it cannot be determined what is returned.
|
||||||
*/
|
*/
|
||||||
private BCField checkGetterIsSubclassable(Method meth, FieldMetaData fmd) {
|
private Field checkGetterIsSubclassable(Method meth, FieldMetaData fmd) {
|
||||||
checkMethodIsSubclassable(meth, fmd);
|
checkMethodIsSubclassable(meth, fmd);
|
||||||
BCField bcField = PCEnhancer.getReturnedField_old(getBCMethod(meth));
|
BCField bcField = PCEnhancer.getReturnedField_old(getBCMethod(meth));
|
||||||
Field field = PCEnhancer.getReturnedField(meth);
|
Field field = PCEnhancer.getReturnedField(classNode, meth);
|
||||||
|
|
||||||
//X TODO remove
|
//X TODO remove
|
||||||
PCEnhancer.assertSameField(field, bcField);
|
PCEnhancer.assertSameField(field, bcField);
|
||||||
|
|
||||||
if (bcField == null) {
|
if (field == null) {
|
||||||
addContractViolation(loc.get("subclasser-invalid-getter", fmd.getName()), fmd);
|
addContractViolation(loc.get("subclasser-invalid-getter", fmd.getName()), fmd);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return bcField;
|
return field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,20 +225,20 @@ public class PCSubclassValidator {
|
||||||
* <code>null</code> if something other than a single field is
|
* <code>null</code> if something other than a single field is
|
||||||
* set, or if it cannot be determined what is set.
|
* set, or if it cannot be determined what is set.
|
||||||
*/
|
*/
|
||||||
private BCField checkSetterIsSubclassable(Method meth, FieldMetaData fmd) {
|
private Field checkSetterIsSubclassable(Method meth, FieldMetaData fmd) {
|
||||||
checkMethodIsSubclassable(meth, fmd);
|
checkMethodIsSubclassable(meth, fmd);
|
||||||
BCField bcField = PCEnhancer.getAssignedField_old(getBCMethod(meth));
|
BCField bcField = PCEnhancer.getAssignedField_old(getBCMethod(meth));
|
||||||
Field field = PCEnhancer.getAssignedField(meth);
|
Field field = PCEnhancer.getAssignedField(classNode, meth);
|
||||||
|
|
||||||
//X TODO remove
|
//X TODO remove
|
||||||
PCEnhancer.assertSameField(field, bcField);
|
PCEnhancer.assertSameField(field, bcField);
|
||||||
|
|
||||||
if (bcField == null) {
|
if (field == null) {
|
||||||
addContractViolation(loc.get("subclasser-invalid-setter", fmd.getName()), fmd);
|
addContractViolation(loc.get("subclasser-invalid-setter", fmd.getName()), fmd);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return bcField;
|
return field;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
package org.apache.openjpa.util.asm;
|
package org.apache.openjpa.util.asm;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.apache.xbean.asm9.ClassReader;
|
import org.apache.xbean.asm9.ClassReader;
|
||||||
|
@ -24,6 +26,7 @@ import org.apache.xbean.asm9.ClassWriter;
|
||||||
import org.apache.xbean.asm9.Opcodes;
|
import org.apache.xbean.asm9.Opcodes;
|
||||||
import org.apache.xbean.asm9.Type;
|
import org.apache.xbean.asm9.Type;
|
||||||
import org.apache.xbean.asm9.tree.AbstractInsnNode;
|
import org.apache.xbean.asm9.tree.AbstractInsnNode;
|
||||||
|
import org.apache.xbean.asm9.tree.ClassNode;
|
||||||
import org.apache.xbean.asm9.tree.VarInsnNode;
|
import org.apache.xbean.asm9.tree.VarInsnNode;
|
||||||
|
|
||||||
import serp.bytecode.BCClass;
|
import serp.bytecode.BCClass;
|
||||||
|
@ -39,6 +42,41 @@ public final class AsmHelper {
|
||||||
// utility class ct
|
// utility class ct
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read the binary bytecode from the class with the given name
|
||||||
|
* @param classBytes the binary of the class
|
||||||
|
* @return the ClassNode constructed from that class
|
||||||
|
*/
|
||||||
|
public static ClassNode readClassNode(byte[] classBytes) {
|
||||||
|
ClassReader cr = new ClassReader(classBytes);
|
||||||
|
ClassNode classNode = new ClassNode();
|
||||||
|
cr.accept(classNode, 0);
|
||||||
|
|
||||||
|
return classNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
ClassNode classNode = new ClassNode();
|
||||||
|
cr.accept(classNode, 0);
|
||||||
|
|
||||||
|
return classNode;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* temporary helper class to convert BCClass to ASM
|
* temporary helper class to convert BCClass to ASM
|
||||||
* @deprecated must get removed when done with migrating from Serp to ASM
|
* @deprecated must get removed when done with migrating from Serp to ASM
|
||||||
|
|
|
@ -24,9 +24,9 @@ import org.apache.openjpa.meta.MetaDataModes;
|
||||||
import org.apache.openjpa.meta.MetaDataRepository;
|
import org.apache.openjpa.meta.MetaDataRepository;
|
||||||
import org.apache.openjpa.persistence.common.apps.Department;
|
import org.apache.openjpa.persistence.common.apps.Department;
|
||||||
import org.apache.openjpa.persistence.common.apps.RuntimeTest2;
|
import org.apache.openjpa.persistence.common.apps.RuntimeTest2;
|
||||||
import org.apache.openjpa.enhance.UnenhancedPropertyAccess;
|
|
||||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||||
import org.apache.openjpa.util.UserException;
|
import org.apache.openjpa.util.asm.AsmHelper;
|
||||||
|
import org.apache.xbean.asm9.tree.ClassNode;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import jakarta.persistence.Access;
|
import jakarta.persistence.Access;
|
||||||
|
@ -34,6 +34,7 @@ import jakarta.persistence.AccessType;
|
||||||
import jakarta.persistence.Basic;
|
import jakarta.persistence.Basic;
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.MappedSuperclass;
|
||||||
import serp.bytecode.BCClass;
|
import serp.bytecode.BCClass;
|
||||||
import serp.bytecode.Project;
|
import serp.bytecode.Project;
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ public class TestSubclassValidator extends SingleEMFTestCase {
|
||||||
setUp("openjpa.RuntimeUnenhancedClasses", "supported",
|
setUp("openjpa.RuntimeUnenhancedClasses", "supported",
|
||||||
Department.class,
|
Department.class,
|
||||||
RuntimeTest2.class,
|
RuntimeTest2.class,
|
||||||
EnhancableGetterEntity.class,
|
EnhanceableGetterEntity.class,
|
||||||
UnenhancedPropertyAccess.class,
|
UnenhancedPropertyAccess.class,
|
||||||
CLEAR_TABLES);
|
CLEAR_TABLES);
|
||||||
}
|
}
|
||||||
|
@ -80,29 +81,31 @@ public class TestSubclassValidator extends SingleEMFTestCase {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
final BCClass bcClass = project.loadClass(EnhancableGetterEntity.class.getName(), tempCl);
|
ClassNode classNode = AsmHelper.readClassNode(EnhanceableGetterEntity.class.getClassLoader(), EnhanceableGetterEntity.class.getName());
|
||||||
final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(EnhancableGetterEntity.class.getName()), tempCl, false);
|
final BCClass bcClass = project.loadClass(EnhanceableGetterEntity.class.getName(), tempCl);
|
||||||
PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, bcClass, log, true);
|
final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(EnhanceableGetterEntity.class.getName()), tempCl, false);
|
||||||
|
PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, classNode, bcClass, log, true);
|
||||||
subclassValidator.assertCanSubclass();
|
subclassValidator.assertCanSubclass();
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
ClassNode classNode = AsmHelper.readClassNode(UnenhancedPropertyAccess.class.getClassLoader(), UnenhancedPropertyAccess.class.getName());
|
||||||
final BCClass bcClass = project.loadClass(UnenhancedPropertyAccess.class.getName(), tempCl);
|
final BCClass bcClass = project.loadClass(UnenhancedPropertyAccess.class.getName(), tempCl);
|
||||||
final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(UnenhancedPropertyAccess.class.getName()), tempCl, false);
|
final ClassMetaData meta = repos.getMetaData(tempCl.loadClass(UnenhancedPropertyAccess.class.getName()), tempCl, false);
|
||||||
PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, bcClass, log, true);
|
PCSubclassValidator subclassValidator = new PCSubclassValidator(meta, classNode, bcClass, log, true);
|
||||||
subclassValidator.assertCanSubclass();
|
subclassValidator.assertCanSubclass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@Access(AccessType.PROPERTY)
|
@Access(AccessType.PROPERTY)
|
||||||
public static class EnhancableGetterEntity {
|
public static class EnhanceableGetterEntity {
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
private String id;
|
private String id;
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
private String name;
|
protected String name;
|
||||||
|
|
||||||
@Basic
|
@Basic
|
||||||
private String another;
|
private String another;
|
||||||
|
|
Loading…
Reference in New Issue