if (generatedMethodName == null) {
throw new RuntimeException("No generated method name found for method '" + method.getMethodName() + "'");
}
// Adds a method which will call the invocationcontext impl
MethodVisitor mv = this.cv.visitMethod(ACC_PUBLIC, generatedMethodName, method.getJMethod().getDescriptor(),
null, method.getJMethod().getExceptions());
boolean webMethodAnnotationPresent = false;
// replay annotations
String nameDesc = MethodRenamer.tryDecode(method.getMethodName()) + method.getJMethod().getDescriptor();
List<AnnotationRecorder> annotationRecorders = this.annotationsOfMethod.get(nameDesc);
if (annotationRecorders != null) {
for (AnnotationRecorder annotationRecorder : annotationRecorders) {
if ("Ljavax/jws/WebMethod;".equals(annotationRecorder.getName())) {
webMethodAnnotationPresent = true;
}
annotationRecorder.replay(mv);
}
}
// parameters annotations
List<ParameterAnnotationRecorder> parameterAnnotationRecorders = this.parametersAnnotationsOfMethod.get(nameDesc);
if (parameterAnnotationRecorders != null) {
for (ParameterAnnotationRecorder parameterAnnotationRecorder : parameterAnnotationRecorders) {
parameterAnnotationRecorder.replay(mv);
}
}
// Add some flags on the generated method
if (!webMethodAnnotationPresent) {
CommonClassGenerator.addAnnotationsOnGeneratedMethod(mv);
}
mv.visitCode();
if (Boolean.getBoolean(EASYBEANS_SHARED_CLASS_FLAG)) {
// if the class is used by other framework, interceptors shouldn't be invoked, so call the renamed method directly.
// if (getEasyBeansFactory() == null) {
// original$MethodHelloWorld();
// }
// if the factory is not null, skip the code and go the easyBeansFactoryNotNullLabel label
Label easyBeansFactoryNotNullLabel = new Label();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKEVIRTUAL, this.classAnnotationMetadata.getClassName(), "getEasyBeansFactory", "()Lorg/ow2/easybeans/api/Factory;");
mv.visitJumpInsn(IFNONNULL, easyBeansFactoryNotNullLabel);
// factory is null, needs to call the original/renamed method
Type[] args = Type.getArgumentTypes(method.getJMethod().getDescriptor());
mv.visitVarInsn(ALOAD, 0);
// for each argument of the methods :
int methodArg = 1;
for (Type type : args) {
int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort());
mv.visitVarInsn(opCode, methodArg);
// Double and Long are special parameters
if (opCode == LLOAD || opCode == DLOAD) {
methodArg++;
}
methodArg++;
}
// Call the original method
mv.visitMethodInsn(INVOKEVIRTUAL, this.classAnnotationMetadata.getClassName(), MethodRenamer.encode(method.getMethodName()), method.getJMethod().getDescriptor());
// Cast and return value
Type returnType = Type.getReturnType(method.getJMethod().getDescriptor());
CommonClassGenerator.addReturnType(returnType, mv);
// if the factory is not null, skip the previous code
mv.visitLabel(easyBeansFactoryNotNullLabel);
}
if (interceptorType == AROUND_INVOKE || interceptorType == POST_CONSTRUCT || interceptorType == PRE_DESTROY) {
// if (getEasyBeansInvocationContextFactory() != null) {
// try {
// return ((Integer) getEasyBeansInvocationContextFactory().getContext(this, getEasyBeansDynamicInterceptorManager(), interceptorType.toString(), "addMethodSignature" , a, b)
// .proceed()).intValue();
// } catch (Exception e) {
// throw new RuntimeException(e);
// }
// }
Label tryLabelStart = new Label();
Label l1 = new Label();
Label l2 = new Label();
mv.visitTryCatchBlock(tryLabelStart, l1, l2, "java/lang/Exception");
// Add bean (as first argument)
mv.visitVarInsn(ALOAD, 0);
// Test if invocation context factory is null
// If there is no invocation context factory, jump to the end
mv.visitMethodInsn(INVOKEVIRTUAL, this.classAnnotationMetadata.getClassName(), "getEasyBeansInvocationContextFactory", "()Lorg/ow2/easybeans/api/interceptor/EZBInvocationContextFactory;");
Label labelNoInvocationContextFactory = new Label();
mv.visitJumpInsn(IFNULL, labelNoInvocationContextFactory);
// Begin of the try block
mv.visitLabel(tryLabelStart);
mv.visitVarInsn(ALOAD, 0);
// There is an invocation context factory, get it
mv.visitMethodInsn(INVOKEVIRTUAL, this.classAnnotationMetadata.getClassName(), "getEasyBeansInvocationContextFactory", "()Lorg/ow2/easybeans/api/interceptor/EZBInvocationContextFactory;");
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 0);
// Get the interceptor manager
mv.visitMethodInsn(INVOKEVIRTUAL, this.classAnnotationMetadata.getClassName(), "getEasyBeansDynamicInterceptorManager", "()Lorg/ow2/easybeans/api/interceptor/EZBInterceptorManager;");
// Add the interceptor type
mv.visitFieldInsn(GETSTATIC, Type.getInternalName(InterceptorType.class), interceptorType.toString(), "Lorg/ow2/util/ee/metadata/ejbjar/api/InterceptorType;");
mv.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(InterceptorType.class), "toString", "()Ljava/lang/String;");
// Signature of the method
mv.visitLdcInsn(MethodHelper.getSignature(method));
// Arguments of the method
// parameters = new Object[] {arg0, arg1, arg...};
// put size of the array
Type[] args = Type.getArgumentTypes(method.getJMethod().getDescriptor());
int methodArg = 1;
mv.visitIntInsn(BIPUSH, args.length);
mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
// for each argument of the methods :
int argCount = 0;
for (Type type : args) {
mv.visitInsn(DUP);
mv.visitIntInsn(BIPUSH, argCount);
int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort());
mv.visitVarInsn(opCode, methodArg);
// Double and Long are special parameters
if (opCode == LLOAD || opCode == DLOAD) {
methodArg++;
}
methodArg++;
// if type is not object type, need to convert it
// for example : Integer.valueOf(i);
CommonClassGenerator.transformPrimitiveIntoObject(type, mv);
mv.visitInsn(AASTORE);
argCount++;
}
Type returnType = Type.getReturnType(method.getJMethod().getDescriptor());
// Call getContext method
mv.visitMethodInsn(INVOKEINTERFACE, "org/ow2/easybeans/api/interceptor/EZBInvocationContextFactory", "getContext", "(Lorg/ow2/easybeans/api/bean/EasyBeansBean;Lorg/ow2/easybeans/api/interceptor/EZBInterceptorManager;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)Lorg/ow2/easybeans/api/EasyBeansInvocationContext;");
// Call of proceed method
mv.visitMethodInsn(INVOKEINTERFACE, "org/ow2/easybeans/api/EasyBeansInvocationContext", "proceed", "()Ljava/lang/Object;");
// Cast and return value
CommonClassGenerator.transformObjectIntoPrimitive(returnType, mv);
mv.visitLabel(l1);
CommonClassGenerator.addReturnType(returnType, mv);
mv.visitLabel(l2);
boolean methodAlreadyThrowJavaLangException = false;
// Catch blocks
String[] methodExceptions = method.getJMethod().getExceptions();
// catch label = exceptions thrown by method + 1
Label[] catchsLabel = null;
if (methodExceptions != null) {
// if the java.lang.Exception is present, don't need two catchs
// blocks
// for java/lang/Exception
if (Arrays.asList(methodExceptions).contains("java/lang/Exception")) {
methodAlreadyThrowJavaLangException = true;
catchsLabel = new Label[methodExceptions.length];
} else {
// else, add a catch for java.lang.Exception
catchsLabel = new Label[methodExceptions.length + 1];
}
} else {
catchsLabel = new Label[1];
}
// init labels
for (int i = 0; i < catchsLabel.length; i++) {
catchsLabel[i] = new Label();
}
// First, do method exceptions (just rethrow the given exception)
int lastCatchBlockLabel = 0;
if (methodAlreadyThrowJavaLangException) {
lastCatchBlockLabel = catchsLabel.length;
} else {
lastCatchBlockLabel = catchsLabel.length - 1;
}
for (int block = 0; block < lastCatchBlockLabel; block++) {
mv.visitLabel(catchsLabel[block]);
mv.visitVarInsn(ASTORE, methodArg);
mv.visitVarInsn(ALOAD, methodArg);
mv.visitInsn(ATHROW);
}
// Now, do the wrapped of Exception into a RuntimeException
if (!methodAlreadyThrowJavaLangException) {
// start label
mv.visitLabel(catchsLabel[lastCatchBlockLabel]);
mv.visitVarInsn(ASTORE, methodArg);
// instanceof RuntimeException
mv.visitVarInsn(ALOAD, methodArg);
mv.visitTypeInsn(INSTANCEOF, "java/lang/RuntimeException");
Label notInstanceOfRuntimeExceptionLabel = new Label();
mv.visitJumpInsn(IFEQ, notInstanceOfRuntimeExceptionLabel);
// throw existing runtime exception (by casting it)
mv.visitVarInsn(ALOAD, methodArg);
mv.visitTypeInsn(CHECKCAST, "java/lang/RuntimeException");
mv.visitInsn(ATHROW);
// build Runtime exception with given exception
mv.visitLabel(notInstanceOfRuntimeExceptionLabel);
mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, methodArg);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
mv.visitInsn(ATHROW);
}
// Perform try/catch blocks with ASM
int block = 0;
// method exception
if (methodExceptions != null) {
for (String exception : methodExceptions) {
mv.visitTryCatchBlock(tryLabelStart, catchsLabel[0], catchsLabel[block], exception);
block++;
}
}
// Exception thrown by proceed() call
if (!methodAlreadyThrowJavaLangException) {
mv.visitTryCatchBlock(tryLabelStart, catchsLabel[0], catchsLabel[lastCatchBlockLabel], "java/lang/Exception");
}
// No invocation context factory end
mv.visitLabel(labelNoInvocationContextFactory);
}
// Start of the Try label of Try/Catch
Label tryLabel = new Label();
mv.visitLabel(tryLabel);
// build new object by calling the constructor
mv.visitTypeInsn(NEW, genInvCtx.getGeneratedClassName());
mv.visitInsn(DUP);
// Add bean (as first argument)
mv.visitVarInsn(ALOAD, 0);
// for each argument
Type[] args = Type.getArgumentTypes(method.getJMethod().getDescriptor());
int methodArg = 1;
for (Type type : args) {
int opCode = CommonClassGenerator.putFieldLoadOpCode(type.getSort());
mv.visitVarInsn(opCode, methodArg);
// Double and Long are special parameters
if (opCode == LLOAD || opCode == DLOAD) {
methodArg++;
}
methodArg++;
}
Type returnType = Type.getReturnType(method.getJMethod().getDescriptor());
String constructorDesc = genInvCtx.getConstructorDesc();
mv.visitMethodInsn(INVOKESPECIAL, genInvCtx.getGeneratedClassName(), "<init>", constructorDesc);
mv.visitMethodInsn(INVOKEVIRTUAL, genInvCtx.getGeneratedClassName(), "proceed", "()Ljava/lang/Object;");
CommonClassGenerator.transformObjectIntoPrimitive(returnType, mv);
CommonClassGenerator.addReturnType(returnType, mv);
boolean methodAlreadyThrowJavaLangException = false;
// Catch blocks
String[] methodExceptions = method.getJMethod().getExceptions();
// catch label = exceptions thrown by method + 1
Label[] catchsLabel = null;
if (methodExceptions != null) {
// if the java.lang.Exception is present, don't need two catchs
// blocks
// for java/lang/Exception
if (Arrays.asList(methodExceptions).contains("java/lang/Exception")) {
methodAlreadyThrowJavaLangException = true;
catchsLabel = new Label[methodExceptions.length];
} else {
// else, add a catch for java.lang.Exception
catchsLabel = new Label[methodExceptions.length + 1];
}
} else {
catchsLabel = new Label[1];
}
// init labels
for (int i = 0; i < catchsLabel.length; i++) {
catchsLabel[i] = new Label();
}
// First, do method exceptions (just rethrow the given exception)
int lastCatchBlockLabel = 0;
if (methodAlreadyThrowJavaLangException) {
lastCatchBlockLabel = catchsLabel.length;
} else {
lastCatchBlockLabel = catchsLabel.length - 1;
}
for (int block = 0; block < lastCatchBlockLabel; block++) {
mv.visitLabel(catchsLabel[block]);
mv.visitVarInsn(ASTORE, methodArg);
mv.visitVarInsn(ALOAD, methodArg);
mv.visitInsn(ATHROW);
}
// Now, do the wrapped of Exception into a RuntimeException
if (!methodAlreadyThrowJavaLangException) {
// start label
mv.visitLabel(catchsLabel[lastCatchBlockLabel]);
mv.visitVarInsn(ASTORE, methodArg);
// instanceof RuntimeException
mv.visitVarInsn(ALOAD, methodArg);
mv.visitTypeInsn(INSTANCEOF, "java/lang/RuntimeException");
Label notInstanceOfRuntimeExceptionLabel = new Label();
mv.visitJumpInsn(IFEQ, notInstanceOfRuntimeExceptionLabel);
// throw existing runtime exception (by casting it)
mv.visitVarInsn(ALOAD, methodArg);
mv.visitTypeInsn(CHECKCAST, "java/lang/RuntimeException");
mv.visitInsn(ATHROW);
// build Runtime exception with given exception
mv.visitLabel(notInstanceOfRuntimeExceptionLabel);
mv.visitTypeInsn(NEW, "java/lang/RuntimeException");
mv.visitInsn(DUP);
mv.visitVarInsn(ALOAD, methodArg);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "(Ljava/lang/Throwable;)V");
mv.visitInsn(ATHROW);
}
// Perform try/catch blocks with ASM
int block = 0;
// method exception
if (methodExceptions != null) {
for (String exception : methodExceptions) {
mv.visitTryCatchBlock(tryLabel, catchsLabel[0], catchsLabel[block], exception);
block++;
}
}
// Exception thrown by proceed() call
if (!methodAlreadyThrowJavaLangException) {
mv.visitTryCatchBlock(tryLabel, catchsLabel[0], catchsLabel[lastCatchBlockLabel], "java/lang/Exception");
}
mv.visitMaxs(0, 0);
mv.visitEnd();
}