All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avaje.ebean.enhance.agent.ClassAdapterEntity Maven / Gradle / Ivy

There is a newer version: 8.1.1
Show newest version
package com.avaje.ebean.enhance.agent;

import com.avaje.ebean.enhance.asm.*;

/**
 * ClassAdapter for enhancing entities.
 * 

* Used for javaagent or ant etc to modify the class with field interception. *

*

* This is NOT used for subclass generation. *

*/ public class ClassAdapterEntity extends ClassVisitor implements EnhanceConstants { private final EnhanceContext enhanceContext; private final ClassLoader classLoader; private final ClassMeta classMeta; private boolean firstMethod = true; public ClassAdapterEntity(ClassVisitor cv, ClassLoader classLoader, EnhanceContext context) { super(Opcodes.ASM5, cv); this.classLoader = classLoader; this.enhanceContext = context; this.classMeta = context.createClassMeta(); } /** * Log that the class has been enhanced. */ public void logEnhanced() { classMeta.logEnhanced(); } public boolean isLog(int level){ return classMeta.isLog(level); } public void log(String msg){ classMeta.log(msg); } /** * Create the class definition replacing the className and super class. */ public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { classMeta.setClassName(name, superName); int n = 1 + interfaces.length; String[] c = new String[n]; for (int i = 0; i < interfaces.length; i++) { c[i] = interfaces[i]; if (c[i].equals(C_ENTITYBEAN)) { classMeta.setEntityBeanInterface(true); } if (c[i].equals(C_SCALAOBJECT)) { classMeta.setScalaInterface(true); } if (c[i].equals(C_GROOVYOBJECT)) { classMeta.setGroovyInterface(true); } } if (classMeta.hasEntityBeanInterface()){ // Just use the original interfaces c = interfaces; } else { // Add the EntityBean interface c[c.length - 1] = C_ENTITYBEAN; if (classMeta.isLog(8)) { classMeta.log("... add EntityBean interface"); } } if (!superName.equals("java/lang/Object")){ // read information about superClasses... if (classMeta.isLog(7)){ classMeta.log("read information about superClasses " + superName + " to see if it is entity/embedded/mappedSuperclass"); } ClassMeta superMeta = enhanceContext.getSuperMeta(superName, classLoader); if (superMeta != null && superMeta.isEntity()){ // the superClass is an entity/embedded/mappedSuperclass... classMeta.setSuperMeta(superMeta); if (classMeta.isLog(3)){ classMeta.log("entity extends "+superMeta.getDescription()); } } else { if (classMeta.isLog(7)){ if (superMeta == null){ classMeta.log("unable to read superMeta for "+superName); } else { classMeta.log("superMeta "+superName+" is not an entity/embedded/mappedsuperclass (with equals or persistent fields)"); } } } } super.visit(version, access, name, signature, superName, c); } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { classMeta.addClassAnnotation(desc); return super.visitAnnotation(desc, visible); } /** * Return true if this is the enhancement marker field. *

* The existence of this field is used to confirm that the class has been * enhanced (rather than solely relying on the EntityBean interface). *

*/ private boolean isEbeanFieldMarker(String name) { return name.equals(MarkerField._EBEAN_MARKER); } private boolean isPropertyChangeListenerField(String desc) { return desc.equals("Ljava/beans/PropertyChangeSupport;"); } /** * The ebeanIntercept field is added once but thats all. Note the other * fields are defined in the superclass. */ public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if ((access & Opcodes.ACC_STATIC) != 0) { // static field... if (isEbeanFieldMarker(name)) { classMeta.setAlreadyEnhanced(true); if (isLog(4)) { log("Found ebean marker field " + name + " " + value); } } else { if (isLog(4)) { log("Skip intercepting static field " + name); } } // no interception of static fields return super.visitField(access, name, desc, signature, value); } if (isPropertyChangeListenerField(desc)) { if (isLog(2)){ classMeta.log("Found existing PropertyChangeSupport field "+name); } // no interception on PropertyChangeSupport field return super.visitField(access, name, desc, signature, value); } if ((access & Opcodes.ACC_TRANSIENT) != 0) { if (isLog(3)){ log("Skip intercepting transient field "+name); } // no interception of transient fields return super.visitField(access, name, desc, signature, value); } // this will hide the field on the super object... // but being in a different ClassLoader means we don't // get access to those 'real' private fields FieldVisitor fv = super.visitField(access, name, desc, signature, value); return classMeta.createLocalFieldVisitor(fv, name, desc); } /** * Replace the method code with field interception. */ public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if (firstMethod){ if (classMeta.isAlreadyEnhanced()) { throw new NoEnhancementRequiredException(); } if (classMeta.hasEntityBeanInterface()){ log("Enhancing when EntityBean interface already exists!"); } // always add the marker field on every enhanced class String marker = MarkerField.addField(cv, classMeta.getClassName()); if (isLog(4)){ log("... add marker field \""+marker+"\""); } IndexFieldWeaver.addPropertiesField(cv); if (isLog(4)){ log("... add _ebean_props field"); } if (!classMeta.isSuperClassEntity()){ // only add the intercept and identity fields if // the superClass is not also enhanced if (isLog(4)){ log("... add intercept and identity fields"); } InterceptField.addField(cv, enhanceContext.isTransientInternalFields()); MethodEquals.addIdentityField(cv); } firstMethod = false; } classMeta.addExistingMethod(name, desc); if (isLog(4)) { log("--- #### method name["+name+"] desc["+desc+"] sig["+signature+"]"); } if (isConstructor(name, desc)) { if (desc.equals("()V")) { // ensure public access on the default constructor access = Opcodes.ACC_PUBLIC; } MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); return new ConstructorAdapter(mv, classMeta, desc); } if (isStaticInit(name, desc)) { if (isLog(4)) { log("... --- #### enhance existing static init method"); } MethodVisitor mv = super.visitMethod(Opcodes.ACC_STATIC, name, desc, signature, exceptions); return new MethodStaticInitAdapter(mv, classMeta); } MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); if (interceptEntityMethod(access, name, desc)) { // change the method replacing the relevant GETFIELD PUTFIELD with // our special field methods with interception... return new MethodFieldAdapter(mv, classMeta, name+" "+desc); } // just leave as is, no interception etc return mv; } /** * Add methods to get and set the entityBeanIntercept. Also add the * writeReplace method to control serialisation. */ public void visitEnd() { if (!classMeta.isEntityEnhancementRequired()){ throw new NoEnhancementRequiredException(); } if (!classMeta.hasStaticInit()) { IndexFieldWeaver.addPropertiesInit(cv, classMeta); } if (!classMeta.hasDefaultConstructor()){ DefaultConstructor.add(cv, classMeta); } MarkerField.addGetMarker(cv, classMeta.getClassName()); if (isLog(4)){ log("... add _ebean_getPropertyNames() and _ebean_getPropertyName()"); } IndexFieldWeaver.addGetPropertyNames(cv, classMeta); IndexFieldWeaver.addGetPropertyName(cv, classMeta); if (!classMeta.isSuperClassEntity()){ if (isLog(8)){ log("... add _ebean_getIntercept() and _ebean_setIntercept()"); } InterceptField.addGetterSetter(cv, classMeta.getClassName()); // Add add/removePropertyChangeListener methods MethodPropertyChangeListener.addMethod(cv, classMeta); } // Add the field set/get methods which are used in place // of GETFIELD PUTFIELD instructions classMeta.addFieldGetSetMethods(cv); //Add the getField(index) and setField(index) methods IndexFieldWeaver.addMethods(cv, classMeta); MethodSetEmbeddedLoaded.addMethod(cv, classMeta); MethodIsEmbeddedNewOrDirty.addMethod(cv, classMeta); MethodNewInstance.addMethod(cv, classMeta); // register with the agentContext enhanceContext.addClassMeta(classMeta); super.visitEnd(); } private boolean isConstructor(String name, String desc){ if (name.equals("")) { if (desc.equals("()V")) { classMeta.setHasDefaultConstructor(true); } return true; } return false; } private boolean isStaticInit(String name, String desc) { if (name.equals("") && desc.equals("()V")) { classMeta.setHasStaticInit(true); return true; } return false; } private boolean interceptEntityMethod(int access, String name, String desc) { if ((access & Opcodes.ACC_STATIC) != 0) { // no interception of static methods? if (isLog(4)){ log("Skip intercepting static method "+name); } return false; } if (name.equals("hashCode") && desc.equals("()I")) { classMeta.setHasEqualsOrHashcode(true); return true; } if (name.equals("equals") && desc.equals("(Ljava/lang/Object;)Z")) { classMeta.setHasEqualsOrHashcode(true); return true; } if (name.equals("toString") && desc.equals("()Ljava/lang/String;")) { // don't intercept toString as its is used // during debugging etc return false; } return true; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy