001package io.ebean.enhance.querybean; 002 003import io.ebean.enhance.asm.MethodVisitor; 004import io.ebean.enhance.asm.Opcodes; 005import io.ebean.enhance.common.EnhanceContext; 006 007import java.util.HashSet; 008import java.util.Set; 009 010import static io.ebean.enhance.querybean.Constants.SET_LABEL; 011 012/** 013 * Adapter that changes GETFIELD calls to type query beans to instead use the generated 014 * 'property access' methods. 015 */ 016public class MethodAdapter extends MethodVisitor implements Opcodes { 017 018 private static Set<String> FINDER_METHODS = new HashSet<>(); 019 020 static { 021 // exclude findEach, findEachWhile which take closures 022 FINDER_METHODS.add("findList"); 023 FINDER_METHODS.add("findSet"); 024 FINDER_METHODS.add("findMap"); 025 FINDER_METHODS.add("findIds"); 026 FINDER_METHODS.add("findCount"); 027 FINDER_METHODS.add("findOne"); 028 FINDER_METHODS.add("findOneOrEmpty"); 029 FINDER_METHODS.add("findSingleAttribute"); 030 FINDER_METHODS.add("findSingleAttributeList"); 031 FINDER_METHODS.add("findIterate"); 032 } 033 034 private final EnhanceContext enhanceContext; 035 036 private final ClassInfo classInfo; 037 038 private final String methodName; 039 040 private boolean labelSet; 041 042 public MethodAdapter(MethodVisitor mv, EnhanceContext enhanceContext, ClassInfo classInfo, String methodName) { 043 super(ASM7, mv); 044 this.enhanceContext = enhanceContext; 045 this.classInfo = classInfo; 046 this.methodName = methodName; 047 } 048 049 @Override 050 public void visitFieldInsn(int opcode, String owner, String name, String desc) { 051 052 if (opcode == GETFIELD && enhanceContext.isQueryBean(owner)) { 053 classInfo.addGetFieldIntercept(owner, name); 054 mv.visitMethodInsn(INVOKEVIRTUAL, owner, "_" + name, "()" + desc, false); 055 } else { 056 super.visitFieldInsn(opcode, owner, name, desc); 057 } 058 } 059 060 @Override 061 public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { 062 063 if (!isInterface && enhanceContext.isEnableQueryAutoLabel()) { 064 if (SET_LABEL.equals(name) && enhanceContext.isQueryBean(owner)) { 065 // label set explicitly in code so don't auto set it 066 labelSet = true; 067 } 068 if (!labelSet && isFinderMethod(name) && enhanceContext.isQueryBean(owner)) { 069 // set a label on the query 070 classInfo.markTypeQueryEnhanced(); 071 mv.visitLdcInsn(classInfo.getShortName() + "." + methodName); 072 mv.visitMethodInsn(INVOKEVIRTUAL, owner, SET_LABEL, "(Ljava/lang/String;)Ljava/lang/Object;", false); 073 mv.visitTypeInsn(CHECKCAST, owner); 074 } 075 } 076 077 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface); 078 } 079 080 private boolean isFinderMethod(String name) { 081 return FINDER_METHODS.contains(name); 082 } 083}