/******************************************************************************* * Copyright (c) 2009, 2012 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.core.java.annotation; import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IMemberValuePair; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.springframework.ide.eclipse.core.java.Introspector; import org.springframework.ide.eclipse.core.java.JdtUtils; import org.springframework.util.ClassUtils; /** * {@link IAnnotationMetadata} implementation that uses Eclipse JDT core model information for * extracting the metadata. * @author Christian Dupuis * @author Leo Dos Santos * @author Martin Lippert * @since 2.2.2 */ public class JdtBasedAnnotationMetadata implements IAnnotationMetadata { private final IType type; private Map<String, Annotation> classAnnotations = new LinkedHashMap<String, Annotation>(); private Map<IMethod, Set<Annotation>> methodAnnotations = new LinkedHashMap<IMethod, Set<Annotation>>(); private Map<IField, Set<Annotation>> fieldAnnotations = new LinkedHashMap<IField, Set<Annotation>>(); private Set<IType> allImplementedInterfaces; public JdtBasedAnnotationMetadata(IType type) { this.type = type; init(); } /** * @Controller("/index.htm") -> value = /index.htm * * @Controller({"/index1.htm" , "/index2.htm"}) -> value = /index1.htm, /index2.htm * * @Controller({ RequestMapping.GET, RequestMapping.POST}) * @Controller({ org.swf.RequestMapping.GET, org.swf.RequestMapping.POST}) -> value = * RequestMapping.GET, RequestMapping.POST * * @Controller(RequestMapping.GET) * @Controller(org.swf.RequestMapping.GET) -> value = RequestMapping.GET */ private void init() { try { for (IAnnotation annotation : Introspector.getAllAnnotations(type)) { Annotation processedAnnotation = processAnnotation(annotation); if (!classAnnotations.containsKey(processedAnnotation.getAnnotationClass())) { classAnnotations.put(processedAnnotation.getAnnotationClass(), processedAnnotation); } } for (IMethod method : Introspector.getAllMethods(type)) { Set<Annotation> modelAnnotations = new LinkedHashSet<Annotation>(); for (IAnnotation annotation : method.getAnnotations()) { modelAnnotations.add(processAnnotation(annotation)); } if (modelAnnotations.size() <= 0) { // If no annotations found on concrete method, look for them on the interface modelAnnotations = processInterfaceMethods(method); } if (modelAnnotations.size() > 0) { methodAnnotations.put(method, modelAnnotations); } } for (IMethod method : Introspector.getAllConstructors(type)) { Set<Annotation> modelAnnotations = new LinkedHashSet<Annotation>(); for (IAnnotation annotation : method.getAnnotations()) { modelAnnotations.add(processAnnotation(annotation)); } if (modelAnnotations.size() > 0) { methodAnnotations.put(method, modelAnnotations); } } for (IField field : Introspector.getAllFields(type)) { Set<Annotation> modelAnnotations = new LinkedHashSet<Annotation>(); for (IAnnotation annotation : field.getAnnotations()) { modelAnnotations.add(processAnnotation(annotation)); } if (modelAnnotations.size() > 0) { fieldAnnotations.put(field, modelAnnotations); } } } catch (JavaModelException e) { } } private Annotation processAnnotation(IAnnotation annotation, IType itype) { Annotation modelAnnotation; if (itype.isBinary()) { modelAnnotation = new Annotation(annotation.getElementName()); } else { IType type = itype; IJavaElement parent = annotation.getParent(); while (parent != null && !(parent instanceof IType)) { parent = parent.getParent(); } if (parent != null) { type = (IType) parent; } modelAnnotation = new Annotation(JdtUtils.resolveClassName(annotation.getElementName(), type)); } try { for (IMemberValuePair member : annotation.getMemberValuePairs()) { StringBuilder builder = new StringBuilder(); // First check if we have an array if (member.getValue() != null && member.getValue().getClass().isArray()) { Object[] values = (Object[]) member.getValue(); for (int i = 0; i < values.length; i++) { processStringValue(member, builder, values[i].toString()); if (i < values.length - 1) { builder.append(", "); } } } // If not process the value directly else if (member.getValue() != null) { processStringValue(member, builder, member.getValue().toString()); } modelAnnotation.addMember(new AnnotationMemberValuePair(("value".equals(member .getMemberName()) ? null : member.getMemberName()), builder.toString())); } } catch (JavaModelException e) { // } return modelAnnotation; } private Annotation processAnnotation(IAnnotation annotation) { return processAnnotation(annotation, type); } private Set<Annotation> processInterfaceMethods(IMethod method) throws JavaModelException { Set<Annotation> modelAnnotations = new LinkedHashSet<Annotation>(); Set<IType> interfaces = getAllImplementedInterfaces(); for (IType iface : interfaces) { IMethod[] interfaceMethod = iface.findMethods(method); if (interfaceMethod != null && interfaceMethod.length > 0) { for (IAnnotation annotation : interfaceMethod[0].getAnnotations()) { modelAnnotations.add(processAnnotation(annotation, iface)); } } } return modelAnnotations; } private Set<IType> getAllImplementedInterfaces() { if (allImplementedInterfaces == null) { allImplementedInterfaces = Introspector.getAllImplementedInterfaces(type); } return allImplementedInterfaces; } private void processStringValue(IMemberValuePair member, StringBuilder builder, String value) { // class value if (member.getValueKind() == IMemberValuePair.K_CLASS) { String className = JdtUtils.resolveClassName(value, type); if (className != null) { builder.append(ClassUtils.getShortName(className)); } else { builder.append(value); } } // enum value else if (member.getValueKind() == IMemberValuePair.K_QUALIFIED_NAME || member.getValueKind() == IMemberValuePair.K_SIMPLE_NAME) { String tempValue = value; int i = tempValue.lastIndexOf('.'); while (i > 0) { tempValue = tempValue.substring(0, i); String className = JdtUtils.resolveClassName(tempValue, type); if (className != null) { builder.append(ClassUtils.getShortName(className)).append( value.substring(i)); break; } } if (builder.length() == 0) { builder.append(value); } } else { builder.append(value); } } public Map<IMethod, Annotation> getMethodLevelAnnotations(String... annotationClasses) { Map<IMethod, Annotation> methodAnnotation = new HashMap<IMethod, Annotation>(); for (Map.Entry<IMethod, Set<Annotation>> entry : methodAnnotations.entrySet()) { for (Annotation annotation : entry.getValue()) { for (String annotationClass : annotationClasses) { if (annotation.getAnnotationClass().equals(annotationClass)) { methodAnnotation.put(entry.getKey(), annotation); } } } } return methodAnnotation; } public boolean hasMethodLevelAnnotations(String... annotationClass) { List<String> annoatations = Arrays.asList(annotationClass); for (Map.Entry<IMethod, Set<Annotation>> entry : methodAnnotations.entrySet()) { for (Annotation annotation : entry.getValue()) { if (annoatations.contains(annotation.getAnnotationClass())) { return true; } } } return false; } public Map<IField, Annotation> getFieldLevelAnnotations(String... annotationClasses) { Map<IField, Annotation> fieldAnnotation = new HashMap<IField, Annotation>(); for (Map.Entry<IField, Set<Annotation>> entry : fieldAnnotations.entrySet()) { for (Annotation annotation : entry.getValue()) { for (String annotationClass : annotationClasses) { if (annotation.getAnnotationClass().equals(annotationClass)) { fieldAnnotation.put(entry.getKey(), annotation); } } } } return fieldAnnotation; } public boolean hasFieldLevelAnnotations(String... annotationClass) { List<String> annoatations = Arrays.asList(annotationClass); for (Map.Entry<IField, Set<Annotation>> entry : fieldAnnotations.entrySet()) { for (Annotation annotation : entry.getValue()) { if (annoatations.contains(annotation.getAnnotationClass())) { return true; } } } return false; } public Set<String> getTypeLevelAnnotationClasses() { return classAnnotations.keySet(); } public Annotation getTypeLevelAnnotation(String annotationClass) { return classAnnotations.get(annotationClass); } public boolean hasTypeLevelAnnotations(String... annotationClasses) { Set<String> foundAnnoatationClasses = getTypeLevelAnnotationClasses(); for (String annotationClass : annotationClasses) { if (foundAnnoatationClasses.contains(annotationClass)) { return true; } } return false; } }