001package io.ebean.enhance.entity;
002
003import io.ebean.enhance.asm.ClassVisitor;
004import io.ebean.enhance.asm.FieldVisitor;
005import io.ebean.enhance.asm.Label;
006import io.ebean.enhance.asm.MethodVisitor;
007import io.ebean.enhance.asm.Opcodes;
008import io.ebean.enhance.common.EnhanceConstants;
009
010/**
011 * Generate the _ebean_getIntercept() method and field.
012 */
013public class InterceptField implements Opcodes, EnhanceConstants {
014
015  /**
016  * Add the _ebean_intercept field.
017  */
018  public static void addField(ClassVisitor cv, boolean transientInternalFields) {
019
020    int access = ACC_PROTECTED + (transientInternalFields ? ACC_TRANSIENT : 0);
021    FieldVisitor f1 = cv.visitField(access, INTERCEPT_FIELD, L_INTERCEPT, null, null);
022    f1.visitEnd();
023  }
024
025  /**
026  * Generate the _ebean_getIntercept() method.
027  * <p>
028  * <pre>
029  * public EntityBeanIntercept _ebean_getIntercept() {
030  *     return _ebean_intercept;
031  * }
032  * </pre>
033  */
034  public static void addGetterSetter(ClassVisitor cv, String className) {
035
036    String lClassName = "L" + className + ";";
037
038    MethodVisitor mv;
039    Label l0, l1;
040
041    mv = cv.visitMethod(ACC_PUBLIC, "_ebean_getIntercept", "()" + L_INTERCEPT, null, null);
042    mv.visitCode();
043    l0 = new Label();
044    mv.visitLabel(l0);
045    mv.visitLineNumber(1, l0);
046    mv.visitVarInsn(ALOAD, 0);
047    mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
048    mv.visitInsn(ARETURN);
049    l1 = new Label();
050    mv.visitLabel(l1);
051    mv.visitLocalVariable("this", lClassName, null, l0, l1, 0);
052    mv.visitMaxs(0, 0);
053    mv.visitEnd();
054
055    addInitInterceptMethod(cv, className);
056  }
057
058  /**
059  * Add _ebean_intercept() method that includes initialisation of the
060  * EntityBeanIntercept.
061  * <p>
062  * This is only required when transientInternalFields=true with enhancement.
063  * In that case the EntityBeanIntercept is transient and can be null after
064  * deserialization - in which case it needs to be initialised.
065  * </p>
066  * <p>
067  * <pre>
068  * public EntityBeanIntercept _ebean_intercept() {
069  *     if (_ebean_intercept == null) {
070  *         _ebean_intercept = new EntityBeanIntercept(this);
071  *     }
072  *     return _ebean_intercept;
073  * }
074  * </pre>
075  */
076  private static void addInitInterceptMethod(ClassVisitor cv, String className) {
077
078    MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "_ebean_intercept", "()" + L_INTERCEPT, null, null);
079    mv.visitCode();
080    Label l0 = new Label();
081    mv.visitLabel(l0);
082    mv.visitLineNumber(1, l0);
083    mv.visitVarInsn(ALOAD, 0);
084    mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
085    Label l1 = new Label();
086    mv.visitJumpInsn(IFNONNULL, l1);
087    Label l2 = new Label();
088    mv.visitLabel(l2);
089    mv.visitLineNumber(2, l2);
090    mv.visitVarInsn(ALOAD, 0);
091    mv.visitTypeInsn(NEW, C_INTERCEPT);
092    mv.visitInsn(DUP);
093    mv.visitVarInsn(ALOAD, 0);
094    mv.visitMethodInsn(INVOKESPECIAL, C_INTERCEPT, INIT, "(Ljava/lang/Object;)V", false);
095    mv.visitFieldInsn(PUTFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
096    mv.visitLabel(l1);
097    mv.visitLineNumber(3, l1);
098    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
099    mv.visitVarInsn(ALOAD, 0);
100    mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
101    mv.visitInsn(ARETURN);
102    Label l3 = new Label();
103    mv.visitLabel(l3);
104    mv.visitLocalVariable("this", "L" + className + ";", null, l0, l3, 0);
105    mv.visitMaxs(4, 1);
106    mv.visitEnd();
107  }
108}