001/* 002 * Copyright 2002-2017 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.core.type.classreading; 018 019import java.util.LinkedHashMap; 020import java.util.Map; 021import java.util.Set; 022 023import org.springframework.asm.AnnotationVisitor; 024import org.springframework.asm.MethodVisitor; 025import org.springframework.asm.Opcodes; 026import org.springframework.asm.SpringAsmInfo; 027import org.springframework.asm.Type; 028import org.springframework.core.annotation.AnnotationAttributes; 029import org.springframework.core.type.MethodMetadata; 030import org.springframework.util.LinkedMultiValueMap; 031import org.springframework.util.MultiValueMap; 032 033/** 034 * ASM method visitor which looks for the annotations defined on a method, 035 * exposing them through the {@link org.springframework.core.type.MethodMetadata} 036 * interface. 037 * 038 * @author Juergen Hoeller 039 * @author Mark Pollack 040 * @author Costin Leau 041 * @author Chris Beams 042 * @author Phillip Webb 043 * @since 3.0 044 */ 045public class MethodMetadataReadingVisitor extends MethodVisitor implements MethodMetadata { 046 047 protected final String methodName; 048 049 protected final int access; 050 051 protected final String declaringClassName; 052 053 protected final String returnTypeName; 054 055 protected final ClassLoader classLoader; 056 057 protected final Set<MethodMetadata> methodMetadataSet; 058 059 protected final Map<String, Set<String>> metaAnnotationMap = new LinkedHashMap<String, Set<String>>(4); 060 061 protected final LinkedMultiValueMap<String, AnnotationAttributes> attributesMap = 062 new LinkedMultiValueMap<String, AnnotationAttributes>(4); 063 064 065 public MethodMetadataReadingVisitor(String methodName, int access, String declaringClassName, 066 String returnTypeName, ClassLoader classLoader, Set<MethodMetadata> methodMetadataSet) { 067 068 super(SpringAsmInfo.ASM_VERSION); 069 this.methodName = methodName; 070 this.access = access; 071 this.declaringClassName = declaringClassName; 072 this.returnTypeName = returnTypeName; 073 this.classLoader = classLoader; 074 this.methodMetadataSet = methodMetadataSet; 075 } 076 077 078 @Override 079 public AnnotationVisitor visitAnnotation(final String desc, boolean visible) { 080 this.methodMetadataSet.add(this); 081 String className = Type.getType(desc).getClassName(); 082 return new AnnotationAttributesReadingVisitor( 083 className, this.attributesMap, this.metaAnnotationMap, this.classLoader); 084 } 085 086 087 @Override 088 public String getMethodName() { 089 return this.methodName; 090 } 091 092 @Override 093 public boolean isAbstract() { 094 return ((this.access & Opcodes.ACC_ABSTRACT) != 0); 095 } 096 097 @Override 098 public boolean isStatic() { 099 return ((this.access & Opcodes.ACC_STATIC) != 0); 100 } 101 102 @Override 103 public boolean isFinal() { 104 return ((this.access & Opcodes.ACC_FINAL) != 0); 105 } 106 107 @Override 108 public boolean isOverridable() { 109 return (!isStatic() && !isFinal() && ((this.access & Opcodes.ACC_PRIVATE) == 0)); 110 } 111 112 @Override 113 public boolean isAnnotated(String annotationName) { 114 return this.attributesMap.containsKey(annotationName); 115 } 116 117 @Override 118 public AnnotationAttributes getAnnotationAttributes(String annotationName) { 119 return getAnnotationAttributes(annotationName, false); 120 } 121 122 @Override 123 public AnnotationAttributes getAnnotationAttributes(String annotationName, boolean classValuesAsString) { 124 AnnotationAttributes raw = AnnotationReadingVisitorUtils.getMergedAnnotationAttributes( 125 this.attributesMap, this.metaAnnotationMap, annotationName); 126 return AnnotationReadingVisitorUtils.convertClassValues( 127 "method '" + getMethodName() + "'", this.classLoader, raw, classValuesAsString); 128 } 129 130 @Override 131 public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName) { 132 return getAllAnnotationAttributes(annotationName, false); 133 } 134 135 @Override 136 public MultiValueMap<String, Object> getAllAnnotationAttributes(String annotationName, boolean classValuesAsString) { 137 if (!this.attributesMap.containsKey(annotationName)) { 138 return null; 139 } 140 MultiValueMap<String, Object> allAttributes = new LinkedMultiValueMap<String, Object>(); 141 for (AnnotationAttributes annotationAttributes : this.attributesMap.get(annotationName)) { 142 AnnotationAttributes convertedAttributes = AnnotationReadingVisitorUtils.convertClassValues( 143 "method '" + getMethodName() + "'", this.classLoader, annotationAttributes, classValuesAsString); 144 for (Map.Entry<String, Object> entry : convertedAttributes.entrySet()) { 145 allAttributes.add(entry.getKey(), entry.getValue()); 146 } 147 } 148 return allAttributes; 149 } 150 151 @Override 152 public String getDeclaringClassName() { 153 return this.declaringClassName; 154 } 155 156 @Override 157 public String getReturnTypeName() { 158 return this.returnTypeName; 159 } 160 161}