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

com.avaje.ebean.enhance.agent.IndexFieldWeaver 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.*;

import java.util.List;

/**
 * Generate the methods based on the list of fields.
 * 

* This includes the createCopy, getField and setField methods etc. *

*/ public class IndexFieldWeaver implements Opcodes { public static void addPropertiesField(ClassVisitor cv) { FieldVisitor fv = cv.visitField(ACC_PUBLIC + ACC_STATIC, "_ebean_props", "[Ljava/lang/String;", null, null); fv.visitEnd(); } public static void addPropertiesInit(ClassVisitor cv, ClassMeta classMeta) { MethodVisitor mv = cv.visitMethod(ACC_STATIC, "", "()V", null, null); mv.visitCode(); addPropertiesInit(mv, classMeta); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(1, l1); mv.visitInsn(RETURN); mv.visitMaxs(4, 0); mv.visitEnd(); } public static void addPropertiesInit(MethodVisitor mv, ClassMeta classMeta) { List fields = classMeta.getAllFields(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); visitIntInsn(mv, fields.size()); mv.visitTypeInsn(ANEWARRAY, "java/lang/String"); if (fields.isEmpty()) { if (classMeta.isLog(3)) { classMeta.log("Has no fields?"); } } else { for (int i=0; i fields = classMeta.getAllFields(); if (fields.isEmpty()) { return; } if (classMeta.isLog(3)) { classMeta.log("fields size:" + fields.size()+" "+fields.toString()); } generateGetField(cv, classMeta, fields, false); generateGetField(cv, classMeta, fields, true); generateSetField(cv, classMeta, fields, false); generateSetField(cv, classMeta, fields, true); if (classMeta.hasEqualsOrHashCode()) { // equals or hashCode is already implemented if (classMeta.isLog(3)) { classMeta.log("... skipping add equals() ... already has equals() hashcode() methods"); } return; } // search for the id field... int idIndex = -1; FieldMeta idFieldMeta = null; // find id field only local to this class for (int i = 0; i < fields.size(); i++) { FieldMeta fieldMeta = fields.get(i); if (fieldMeta.isId() && fieldMeta.isLocalField(classMeta)) { if (idIndex == -1) { // we have found an id field idIndex = i; idFieldMeta = fieldMeta; } else { // there are 2 or more id fields idIndex = -2; } } } if (idIndex == -2) { // there are 2 or more id fields? if (classMeta.isLog(1)) { classMeta.log("has 2 or more id fields. Not adding equals() method."); } } else if (idIndex == -1) { // there are no id fields local to this type if (classMeta.isLog(3)) { classMeta.log("has no id fields on this type. Not adding equals() method. Expected when Id property on superclass."); } } else { // add the _ebean_getIdentity(), equals() and hashCode() methods MethodEquals.addMethods(cv, classMeta, idIndex, idFieldMeta); } } /** * Generate the invokeGet method. */ private static void generateGetField(ClassVisitor cv, ClassMeta classMeta, List fields, boolean intercept) { String className = classMeta.getClassName(); MethodVisitor mv; if (intercept) { mv = cv.visitMethod(ACC_PUBLIC, "_ebean_getFieldIntercept", "(I)Ljava/lang/Object;",null, null); } else { mv = cv.visitMethod(ACC_PUBLIC, "_ebean_getField", "(I)Ljava/lang/Object;", null, null); } mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); mv.visitVarInsn(ILOAD, 1); Label[] switchLabels = new Label[fields.size()]; for (int i = 0; i < switchLabels.length; i++) { switchLabels[i] = new Label(); } int maxIndex = switchLabels.length - 1; Label labelException = new Label(); mv.visitTableSwitchInsn(0, maxIndex, labelException, switchLabels); for (int i = 0; i < fields.size(); i++) { FieldMeta fieldMeta = fields.get(i); mv.visitLabel(switchLabels[i]); mv.visitLineNumber(1, switchLabels[i]); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 0); fieldMeta.appendSwitchGet(mv, classMeta, intercept); mv.visitInsn(ARETURN); } mv.visitLabel(labelException); mv.visitLineNumber(1, labelException); mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); mv.visitInsn(DUP); mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); mv.visitLdcInsn("Invalid index "); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "(Ljava/lang/String;)V", false); mv.visitVarInsn(ILOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/String;)V", false); mv.visitInsn(ATHROW); Label l5 = new Label(); mv.visitLabel(l5); mv.visitLocalVariable("this", "L" + className + ";", null, l0, l5, 0); mv.visitLocalVariable("index", "I", null, l0, l5, 1); mv.visitMaxs(5, 2); mv.visitEnd(); } /** * Generate the _ebean_setField or _ebean_setFieldBypass method. *

* Bypass will bypass the interception. The interception checks that the * property has been loaded and creates oldValues if the bean is being made * dirty for the first time. *

*/ private static void generateSetField(ClassVisitor cv, ClassMeta classMeta, List fields,boolean intercept) { String className = classMeta.getClassName(); MethodVisitor mv; if (intercept) { mv = cv.visitMethod(ACC_PUBLIC, "_ebean_setFieldIntercept", "(ILjava/lang/Object;)V", null, null); } else { mv = cv.visitMethod(ACC_PUBLIC, "_ebean_setField", "(ILjava/lang/Object;)V", null, null); } mv.visitCode(); Label l0 = new Label(); mv.visitLabel(l0); mv.visitLineNumber(1, l0); Label l1 = new Label(); mv.visitLabel(l1); mv.visitLineNumber(1, l1); mv.visitVarInsn(ILOAD, 1); Label[] switchLabels = new Label[fields.size()]; for (int i = 0; i < switchLabels.length; i++) { switchLabels[i] = new Label(); } Label labelException = new Label(); int maxIndex = switchLabels.length - 1; mv.visitTableSwitchInsn(0, maxIndex, labelException, switchLabels); for (int i = 0; i < fields.size(); i++) { FieldMeta fieldMeta = fields.get(i); mv.visitLabel(switchLabels[i]); mv.visitLineNumber(1, switchLabels[i]); mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 2); fieldMeta.appendSwitchSet(mv, classMeta, intercept); Label l6 = new Label(); mv.visitLabel(l6); mv.visitLineNumber(1, l6); mv.visitInsn(RETURN); } mv.visitLabel(labelException); mv.visitLineNumber(1, labelException); mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); mv.visitInsn(DUP); mv.visitTypeInsn(NEW, "java/lang/StringBuilder"); mv.visitInsn(DUP); mv.visitLdcInsn("Invalid index "); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "", "(Ljava/lang/String;)V", false); mv.visitVarInsn(ILOAD, 1); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "", "(Ljava/lang/String;)V", false); mv.visitInsn(ATHROW); Label l9 = new Label(); mv.visitLabel(l9); mv.visitLocalVariable("this", "L" + className + ";", null, l0, l9, 0); mv.visitLocalVariable("index", "I", null, l0, l9, 1); mv.visitLocalVariable("o", "Ljava/lang/Object;", null, l0, l9, 2); mv.visitLocalVariable("arg", "Ljava/lang/Object;", null, l0, l9, 3); mv.visitLocalVariable("p", "L" + className + ";", null, l1, l9, 4); mv.visitMaxs(5, 5); mv.visitEnd(); } /** * Helper method for visiting an int value. *

* This can use special constant values for int values from 0 to 5. *

*/ public static void visitIntInsn(MethodVisitor mv, int value) { switch (value) { case 0: mv.visitInsn(ICONST_0); break; case 1: mv.visitInsn(ICONST_1); break; case 2: mv.visitInsn(ICONST_2); break; case 3: mv.visitInsn(ICONST_3); break; case 4: mv.visitInsn(ICONST_4); break; case 5: mv.visitInsn(ICONST_5); break; default: if (value <= Byte.MAX_VALUE){ mv.visitIntInsn(BIPUSH, value); } else { mv.visitIntInsn(SIPUSH, value); } } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy