001package io.ebean.enhance.entity;
002
003import io.ebean.enhance.asm.ClassVisitor;
004import io.ebean.enhance.asm.Label;
005import io.ebean.enhance.asm.MethodVisitor;
006import io.ebean.enhance.asm.Opcodes;
007import io.ebean.enhance.common.ClassMeta;
008import io.ebean.enhance.common.EnhanceConstants;
009
010import java.util.List;
011
012/**
013 * Used to detect if a class has been enhanced.
014 * <p>
015 * Moved to use this over just relying on the existence of the EntityBean interface
016 * to make the enhancement more robust.
017 * </p>
018 */
019public class MethodIsEmbeddedNewOrDirty implements Opcodes, EnhanceConstants {
020
021  /**
022  * Generate the _ebean_isEmbeddedNewOrDirty() method.
023  *
024  * <pre>
025  * public boolean _ebean_isEmbeddedNewOrDirty() {
026  *  // for each embedded bean field...
027  *     if (entityBeanIntercept.isEmbeddedNewOrDirty(embeddedBeanField)) return true;
028  *  ...
029  *  return false;
030  * }
031  * </pre>
032  */
033  public static void addMethod(ClassVisitor cv, ClassMeta classMeta) {
034
035    String className = classMeta.getClassName();
036
037    MethodVisitor mv;
038
039    mv = cv.visitMethod(ACC_PUBLIC, "_ebean_isEmbeddedNewOrDirty", "()Z", null, null);
040    mv.visitCode();
041
042    Label labelBegin = null;
043
044    Label labelNext = null;
045
046    List<FieldMeta> allFields = classMeta.getAllFields();
047    for (int i = 0; i < allFields.size(); i++) {
048      FieldMeta fieldMeta = allFields.get(i);
049      if (fieldMeta.isEmbedded()){
050
051        Label l0 = labelNext;
052        if (l0 == null) {
053          l0 = new Label();
054        }
055        if (labelBegin == null){
056          labelBegin = l0;
057        }
058
059        mv.visitLabel(l0);
060        mv.visitLineNumber(0, l0);
061        if (i > 0) {
062          mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
063        }
064        mv.visitVarInsn(ALOAD, 0);
065        mv.visitFieldInsn(GETFIELD, className, INTERCEPT_FIELD, L_INTERCEPT);
066        mv.visitVarInsn(ALOAD, 0);
067        fieldMeta.appendSwitchGet(mv, classMeta, false);
068        mv.visitMethodInsn(INVOKEVIRTUAL, C_INTERCEPT, "isEmbeddedNewOrDirty", "(Ljava/lang/Object;)Z", false);
069
070        labelNext = new Label();
071        mv.visitJumpInsn(IFEQ, labelNext);
072        mv.visitInsn(ICONST_1);
073        mv.visitInsn(IRETURN);
074
075      }
076    }
077
078    if (labelNext == null){
079      labelNext = new Label();
080    }
081    if (labelBegin == null){
082      labelBegin = labelNext;
083    }
084    mv.visitLabel(labelNext);
085    mv.visitLineNumber(1, labelNext);
086    mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
087    mv.visitInsn(ICONST_0);
088    mv.visitInsn(IRETURN);
089
090    Label l3 = new Label();
091    mv.visitLabel(l3);
092    mv.visitLocalVariable("this", "L"+className+";", null, labelBegin, l3, 0);
093    mv.visitMaxs(2, 1);
094    mv.visitEnd();
095
096  }
097}