package com.aggrepoint.winlet.spring; import org.objectweb.asm.AnnotationVisitor; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.springframework.web.bind.annotation.RequestMapping; import com.aggrepoint.winlet.spring.annotation.Action; import com.aggrepoint.winlet.spring.annotation.Window; import com.aggrepoint.winlet.spring.annotation.Winlet; /** * 对使用了@Winlet注解的类进行以下处理: * * <pre> * 1) 若类上定义了RequestMapping注解,则将其去除 * 2) 为类添加RequestMapping注解 * !! 3) 若方法上定义了@RequestMapping注解,则将注解去除 !! - 20150917 不去除 - Winlet中也可以直接定义@RequestMapping方法 * 4) 若@Window注解没有指明value,则将其方法名替换为value * 5) 对于所有@Window注解,创建对应的RequestMapping注解 * 6) 若Action注解没有指明value,则将其方法名替换为value * </pre> * * @author Jiangming Yang (yangjm@gmail.com) */ public class WinletClassVisitor extends ClassVisitor implements Opcodes { static String getClassDesc(Class<?> c) { String str = c.getName().replaceAll("\\.", "/"); return "L" + str + ";"; } final String DESC_WINLET = getClassDesc(Winlet.class); final String DESC_ACTION = getClassDesc(Action.class); final String DESC_WINDOW = getClassDesc(Window.class); final String DESC_REQUEST_MAPPING = getClassDesc(RequestMapping.class); String winletPath = ""; boolean hasWindow = false; boolean hasAction = false; public WinletClassVisitor(ClassVisitor inner) { super(ASM5, inner); } public boolean isWinlet() { return !"".equals(winletPath) || hasWindow || hasAction; } @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (DESC_REQUEST_MAPPING.equals(desc)) { // 若类上使用了@RequestMapping注解,将其去除 return null; } else if (DESC_WINLET.equals(desc)) { // 处理@Winlet注解 return new AnnotationVisitor(ASM5, cv.visitAnnotation(desc, visible)) { public void visit(String name, Object value) { super.visit(name, value); // 提取@Winlet注解value if ("value".equals(name)) winletPath = value.toString(); } public void visitEnd() { super.visitEnd(); if (!isWinlet()) return; // 加入@RequestMapping注解 av = cv.visitAnnotation(DESC_REQUEST_MAPPING, true); AnnotationVisitor av1 = av.visitArray("value"); av1.visit(null, winletPath.startsWith("/") ? winletPath : "/" + winletPath); av1.visitEnd(); av.visitEnd(); } }; } return cv.visitAnnotation(desc, visible); } @Override public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { final String methodName = name; return new MethodVisitor(ASM5, super.visitMethod(access, name, desc, signature, exceptions)) { @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { if (DESC_WINDOW.equals(desc)) { hasWindow = true; // 1. 在@Window之前添加@RequestMapping // 2. 当@Window没有指定value()时,取方法的名称作为value()的值 final AnnotationVisitor theAv = mv.visitAnnotation( DESC_REQUEST_MAPPING, visible); return new AnnotationVisitor(ASM5) { String value = methodName; /** * Get value() of @Window annotation */ @Override public void visit(String name, Object value) { if ("value".equals(name) && !"".equals(value.toString())) this.value = value.toString(); } /** * Replace @Window value() string with RequestMapping * value() string array */ @Override public void visitEnd() { AnnotationVisitor av1 = theAv.visitArray("value"); av1.visit(null, "/" + value); av1.visitEnd(); theAv.visitEnd(); av1 = mv.visitAnnotation(DESC_WINDOW, true); av1.visit("value", value); av1.visitEnd(); } }; } else if (DESC_ACTION.equals(desc)) { hasAction = true; // 当@Action没有指定value()时,取方法的名称作为value()的值 return new AnnotationVisitor(ASM5, mv.visitAnnotation(desc, visible)) { boolean visited = false; @Override public void visit(String name, Object value) { if ("value".equals(name)) { if ("".equals(value.toString())) super.visit(name, methodName); else super.visit(name, value); visited = true; } } @Override public void visitEnd() { if (!visited) super.visit("value", methodName); } }; } return mv.visitAnnotation(desc, visible); } }; } }