001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements.  See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership.  The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the
007     * "License"); you may not use this file except in compliance
008     * with the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing,
013     * software distributed under the License is distributed on an
014     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     * KIND, either express or implied.  See the License for the
016     * specific language governing permissions and limitations
017     * under the License.
018     */
019    package org.apache.shiro.aop;
020    
021    import java.lang.annotation.Annotation;
022    import java.lang.reflect.Method;
023    
024    /**
025     * Default {@code AnnotationResolver} implementation that merely inspects the
026     * {@link MethodInvocation MethodInvocation}'s {@link MethodInvocation#getMethod() target method},
027     * and returns {@code targetMethod}.{@link Method#getAnnotation(Class) getAnnotation(class)}.
028     * <p/>
029     * Unfortunately Java's default reflection API for Annotations is not very robust, and this logic
030     * may not be enough - if the incoming method invocation represents a method from an interface,
031     * this default logic would not discover the annotation if it existed on the method implementation
032     * directly (as opposed to being defined directly in the interface definition).
033     * <p/>
034     * More complex class hierarchy traversal logic is required to exhaust a method's target object's
035     * classes, parent classes, interfaces and parent interfaces.  That logic will likely be added
036     * to this implementation in due time, but for now, this implementation relies on the JDK's default
037     * {@link Method#getAnnotation(Class) Method.getAnnotation(class)} logic.
038     *
039     * @since 1.1
040     */
041    public class DefaultAnnotationResolver implements AnnotationResolver {
042    
043        /**
044         * Returns {@code methodInvocation.}{@link org.apache.shiro.aop.MethodInvocation#getMethod() getMethod()}.{@link Method#getAnnotation(Class) getAnnotation(clazz)}.
045         *
046         * @param mi    the intercepted method to be invoked.
047         * @param clazz the annotation class to use to find an annotation instance on the method.
048         * @return the discovered annotation or {@code null} if an annotation instance could not be
049         *         found.
050         */
051        public Annotation getAnnotation(MethodInvocation mi, Class<? extends Annotation> clazz) {
052            if (mi == null) {
053                throw new IllegalArgumentException("method argument cannot be null");
054            }
055            Method m = mi.getMethod();
056            if (m == null) {
057                String msg = MethodInvocation.class.getName() + " parameter incorrectly constructed.  getMethod() returned null";
058                throw new IllegalArgumentException(msg);
059    
060            }
061            Annotation annotation = m.getAnnotation(clazz);
062            return annotation == null ? mi.getThis().getClass().getAnnotation(clazz) : annotation;
063        }
064    }