001/*002 * Copyright 2002-2019 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 at007 *008 * https://www.apache.org/licenses/LICENSE-2.0009 *010 * Unless required by applicable law or agreed to in writing, software011 * 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 and014 * limitations under the License.015 */016017package org.springframework.aop.aspectj.annotation;018019import java.io.IOException;020import java.io.ObjectInputStream;021import java.io.Serializable;022023import org.aspectj.lang.annotation.Aspect;024import org.aspectj.lang.reflect.AjType;025import org.aspectj.lang.reflect.AjTypeSystem;026import org.aspectj.lang.reflect.PerClauseKind;027028import org.springframework.aop.Pointcut;029import org.springframework.aop.aspectj.AspectJExpressionPointcut;030import org.springframework.aop.aspectj.TypePatternClassFilter;031import org.springframework.aop.framework.AopConfigException;032import org.springframework.aop.support.ComposablePointcut;033034/**035 * Metadata for an AspectJ aspect class, with an additional Spring AOP pointcut036 * for the per clause.037 *038 * <p>Uses AspectJ 5 AJType reflection API, enabling us to work with different039 * AspectJ instantiation models such as "singleton", "pertarget" and "perthis".040 *041 * @author Rod Johnson042 * @author Juergen Hoeller043 * @since 2.0044 * @see org.springframework.aop.aspectj.AspectJExpressionPointcut045 */046@SuppressWarnings("serial")047public class AspectMetadata implements Serializable {048049 /**050 * The name of this aspect as defined to Spring (the bean name) -051 * allows us to determine if two pieces of advice come from the052 * same aspect and hence their relative precedence.053 */054 private final String aspectName;055056 /**057 * The aspect class, stored separately for re-resolution of the058 * corresponding AjType on deserialization.059 */060 private final Class<?> aspectClass;061062 /**063 * AspectJ reflection information (AspectJ 5 / Java 5 specific).064 * Re-resolved on deserialization since it isn't serializable itself.065 */066 private transient AjType<?> ajType;067068 /**069 * Spring AOP pointcut corresponding to the per clause of the070 * aspect. Will be the Pointcut.TRUE canonical instance in the071 * case of a singleton, otherwise an AspectJExpressionPointcut.072 */073 private final Pointcut perClausePointcut;074075076 /**077 * Create a new AspectMetadata instance for the given aspect class.078 * @param aspectClass the aspect class079 * @param aspectName the name of the aspect080 */081 public AspectMetadata(Class<?> aspectClass, String aspectName) {082 this.aspectName = aspectName;083084 Class<?> currClass = aspectClass;085 AjType<?> ajType = null;086 while (currClass != Object.class) {087 AjType<?> ajTypeToCheck = AjTypeSystem.getAjType(currClass);088 if (ajTypeToCheck.isAspect()) {089 ajType = ajTypeToCheck;090 break;091 }092 currClass = currClass.getSuperclass();093 }094 if (ajType == null) {095 throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect");096 }097 if (ajType.getDeclarePrecedence().length > 0) {098 throw new IllegalArgumentException("DeclarePrecedence not presently supported in Spring AOP");099 }100 this.aspectClass = ajType.getJavaClass();101 this.ajType = ajType;102103 switch (this.ajType.getPerClause().getKind()) {104 case SINGLETON:105 this.perClausePointcut = Pointcut.TRUE;106 return;107 case PERTARGET:108 case PERTHIS:109 AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut();110 ajexp.setLocation(aspectClass.getName());111 ajexp.setExpression(findPerClause(aspectClass));112 ajexp.setPointcutDeclarationScope(aspectClass);113 this.perClausePointcut = ajexp;114 return;115 case PERTYPEWITHIN:116 // Works with a type pattern117 this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass)));118 return;119 default:120 throw new AopConfigException(121 "PerClause " + ajType.getPerClause().getKind() + " not supported by Spring AOP for " + aspectClass);122 }123 }124125 /**126 * Extract contents from String of form {@code pertarget(contents)}.127 */128 private String findPerClause(Class<?> aspectClass) {129 String str = aspectClass.getAnnotation(Aspect.class).value();130 int beginIndex = str.indexOf('(') + 1;131 int endIndex = str.length() - 1;132 return str.substring(beginIndex, endIndex);133 }134135136 /**137 * Return AspectJ reflection information.138 */139 public AjType<?> getAjType() {140 return this.ajType;141 }142143 /**144 * Return the aspect class.145 */146 public Class<?> getAspectClass() {147 return this.aspectClass;148 }149150 /**151 * Return the aspect name.152 */153 public String getAspectName() {154 return this.aspectName;155 }156157 /**158