/*******************************************************************************
* Copyright (c) 2007, 2013 Spring IDE Developers
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.aop.core.internal.model.builder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.FieldVisitor;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
import org.springframework.ide.eclipse.aop.core.internal.model.AnnotationAspectDefinition;
import org.springframework.ide.eclipse.aop.core.internal.model.AnnotationIntroductionDefinition;
import org.springframework.ide.eclipse.aop.core.model.IAopReference.ADVICE_TYPE;
import org.springframework.ide.eclipse.aop.core.model.IAspectDefinition;
import org.springframework.ide.eclipse.core.type.asm.EmptyAnnotationVisitor;
import org.springframework.ide.eclipse.core.type.asm.EmptyFieldVisitor;
import org.springframework.ide.eclipse.core.type.asm.EmptyMethodVisitor;
import org.springframework.util.StringUtils;
/**
* ASM-based Visitor that collects all <code>@AspectJ<code>-style annotations
*
* @author Christian Dupuis
* @author Torsten Juergeleit
* @author Martin Lippert
* @since 2.0
*/
public class AdviceAnnotationVisitor extends ClassVisitor {
private static final String BEFORE_ANNOTATION_DESC = Type.getDescriptor(Before.class);
private static final String AFTER_ANNOTATION_DESC = Type.getDescriptor(After.class);
private static final String AFTERRETURNING_ANNOTATION_DESC = Type.getDescriptor(AfterReturning.class);
private static final String AFTERTHROWING_ANNOTATION_DESC = Type.getDescriptor(AfterThrowing.class);
private static final String AROUND_ANNOTATION_DESC = Type.getDescriptor(Around.class);
private static final String DECLARE_PARENTS_ANNOTATION_DESC = Type.getDescriptor(DeclareParents.class);
private static Map<String, ADVICE_TYPE> ANNOTATION_TYPES = null;
static {
ANNOTATION_TYPES = new HashMap<String, ADVICE_TYPE>();
ANNOTATION_TYPES.put(BEFORE_ANNOTATION_DESC, ADVICE_TYPE.BEFORE);
ANNOTATION_TYPES.put(AFTER_ANNOTATION_DESC, ADVICE_TYPE.AFTER);
ANNOTATION_TYPES.put(AFTERRETURNING_ANNOTATION_DESC, ADVICE_TYPE.AFTER_RETURNING);
ANNOTATION_TYPES.put(AFTERTHROWING_ANNOTATION_DESC, ADVICE_TYPE.AFTER_THROWING);
ANNOTATION_TYPES.put(AROUND_ANNOTATION_DESC, ADVICE_TYPE.AROUND);
ANNOTATION_TYPES.put(DECLARE_PARENTS_ANNOTATION_DESC, ADVICE_TYPE.DECLARE_PARENTS);
}
private List<IAspectDefinition> aspectDefinitions = new ArrayList<IAspectDefinition>();
private int aspectStartLineNumber;
private int aspectEndLineNumber;
private String aspectName;
private String aspectClassName;
public AdviceAnnotationVisitor(String aspectName, String aspectClassName, int aspectStartLineNumber, int aspectEndLineNumber) {
super(SpringAsmInfo.ASM_VERSION);
this.aspectStartLineNumber = aspectStartLineNumber;
this.aspectEndLineNumber = aspectEndLineNumber;
this.aspectName = aspectName;
this.aspectClassName = aspectClassName;
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
Type[] types = Type.getArgumentTypes(desc);
StringBuffer buf = new StringBuffer(name);
if (types != null && types.length > 0) {
buf.append("(");
for (int i = 0; i < types.length; i++) {
Type type = types[i];
buf.append(type.getClassName());
if (i < (types.length - 1)) {
buf.append(", ");
}
}
buf.append(")");
}
final String visitedMethod = buf.toString();
return new EmptyMethodVisitor() {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (visible && ANNOTATION_TYPES.containsKey(desc)) {
final AnnotationAspectDefinition def = new AnnotationAspectDefinition();
aspectDefinitions.add(def);
def.setAspectClassName(aspectClassName);
def.setAdviceMethodName(visitedMethod);
def.setAspectStartLineNumber(aspectStartLineNumber);
def.setAspectEndLineNumber(aspectEndLineNumber);
def.setAspectName(aspectName);
def.setType(ANNOTATION_TYPES.get(desc));
return new EmptyAnnotationVisitor() {
@Override
public void visit(String name, Object value) {
if ("value".equals(name) || "pointcut".equals(name)) {
def.setPointcutExpression(value.toString());
} else if ("argNames".equals(name)) {
def.setArgNames(StringUtils.commaDelimitedListToStringArray(value.toString()));
} else if ("returning".equals(name)) {
def.setReturning(value.toString());
} else if ("throwing".equals(name)) {
def.setThrowing(value.toString());
}
}
};
}
else {
return new EmptyAnnotationVisitor();
}
}
};
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
final String visitedField = name;
final String visitedFieldType = Type.getType(desc).getClassName();
return new EmptyFieldVisitor() {
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
if (visible && ANNOTATION_TYPES.containsKey(desc)) {
final AnnotationIntroductionDefinition def = new AnnotationIntroductionDefinition();
aspectDefinitions.add(def);
def.setDefiningField(visitedField);
def.setIntroducedInterfaceName(visitedFieldType);
def.setAspectClassName(aspectClassName);
def.setAspectName(aspectName);
def.setAspectStartLineNumber(aspectStartLineNumber);
def.setAspectEndLineNumber(aspectEndLineNumber);
return new EmptyAnnotationVisitor() {
public void visit(String name, Object value) {
if ("defaultImpl".equals(name)) {
def.setDefaultImplName(value.toString());
} else if ("value".equals(name)) {
def.setTypePattern(value.toString());
}
};
};
}
else {
return new EmptyAnnotationVisitor();
}
}
};
}
public List<IAspectDefinition> getAspectDefinitions() {
return aspectDefinitions;
}
}