001/*
002 * Copyright 2002-2018 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.aop.aspectj;
018
019import org.aopalliance.aop.Advice;
020
021import org.springframework.aop.ClassFilter;
022import org.springframework.aop.IntroductionAdvisor;
023import org.springframework.aop.IntroductionInterceptor;
024import org.springframework.aop.support.ClassFilters;
025import org.springframework.aop.support.DelegatePerTargetObjectIntroductionInterceptor;
026import org.springframework.aop.support.DelegatingIntroductionInterceptor;
027
028/**
029 * Introduction advisor delegating to the given object.
030 * Implements AspectJ annotation-style behavior for the DeclareParents annotation.
031 *
032 * @author Rod Johnson
033 * @author Ramnivas Laddad
034 * @since 2.0
035 */
036public class DeclareParentsAdvisor implements IntroductionAdvisor {
037
038        private final Advice advice;
039
040        private final Class<?> introducedInterface;
041
042        private final ClassFilter typePatternClassFilter;
043
044
045        /**
046         * Create a new advisor for this DeclareParents field.
047         * @param interfaceType static field defining the introduction
048         * @param typePattern type pattern the introduction is restricted to
049         * @param defaultImpl the default implementation class
050         */
051        public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Class<?> defaultImpl) {
052                this(interfaceType, typePattern,
053                                new DelegatePerTargetObjectIntroductionInterceptor(defaultImpl, interfaceType));
054        }
055
056        /**
057         * Create a new advisor for this DeclareParents field.
058         * @param interfaceType static field defining the introduction
059         * @param typePattern type pattern the introduction is restricted to
060         * @param delegateRef the delegate implementation object
061         */
062        public DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, Object delegateRef) {
063                this(interfaceType, typePattern, new DelegatingIntroductionInterceptor(delegateRef));
064        }
065
066        /**
067         * Private constructor to share common code between impl-based delegate and reference-based delegate
068         * (cannot use method such as init() to share common code, due the use of final fields)
069         * @param interfaceType static field defining the introduction
070         * @param typePattern type pattern the introduction is restricted to
071         * @param interceptor the delegation advice as {@link IntroductionInterceptor}
072         */
073        private DeclareParentsAdvisor(Class<?> interfaceType, String typePattern, IntroductionInterceptor interceptor) {
074                this.advice = interceptor;
075                this.introducedInterface = interfaceType;
076
077                // Excludes methods implemented.
078                ClassFilter typePatternFilter = new TypePatternClassFilter(typePattern);
079                ClassFilter exclusion = new ClassFilter() {
080                        @Override
081                        public boolean matches(Class<?> clazz) {
082                                return !introducedInterface.isAssignableFrom(clazz);
083                        }
084                };
085                this.typePatternClassFilter = ClassFilters.intersection(typePatternFilter, exclusion);
086        }
087
088
089        @Override
090        public ClassFilter getClassFilter() {
091                return this.typePatternClassFilter;
092        }
093
094        @Override
095        public void validateInterfaces() throws IllegalArgumentException {
096                // Do nothing
097        }
098
099        @Override
100        public boolean isPerInstance() {
101                return true;
102        }
103
104        @Override
105        public Advice getAdvice() {
106                return this.advice;
107        }
108
109        @Override
110        public Class<?>[] getInterfaces() {
111                return new Class<?>[] {this.introducedInterface};
112        }
113
114}