All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cn.taketoday.aop.aspectj.annotation.AspectMetadata Maven / Gradle / Ivy

/*
 * Original Author -> Harry Yang ([email protected]) https://taketoday.cn
 * Copyright © TODAY & 2017 - 2022 All Rights Reserved.
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see [http://www.gnu.org/licenses/]
 */

package cn.taketoday.aop.aspectj.annotation;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.AjType;
import org.aspectj.lang.reflect.AjTypeSystem;
import org.aspectj.lang.reflect.PerClauseKind;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serial;
import java.io.Serializable;

import cn.taketoday.aop.Pointcut;
import cn.taketoday.aop.aspectj.AspectJExpressionPointcut;
import cn.taketoday.aop.aspectj.TypePatternClassFilter;
import cn.taketoday.aop.framework.AopConfigException;
import cn.taketoday.aop.support.ComposablePointcut;

/**
 * Metadata for an AspectJ aspect class, with an additional Framework AOP pointcut
 * for the per clause.
 *
 * 

Uses AspectJ 5 AJType reflection API, enabling us to work with different * AspectJ instantiation models such as "singleton", "pertarget" and "perthis". * * @author Rod Johnson * @author Juergen Hoeller * @see AspectJExpressionPointcut * @since 4.0 */ public class AspectMetadata implements Serializable { /** * The name of this aspect as defined to Framework (the bean name) - * allows us to determine if two pieces of advice come from the * same aspect and hence their relative precedence. */ private final String aspectName; /** * The aspect class, stored separately for re-resolution of the * corresponding AjType on deserialization. */ private final Class aspectClass; /** * AspectJ reflection information (AspectJ 5 / Java 5 specific). * Re-resolved on deserialization since it isn't serializable itself. */ private transient AjType ajType; /** * Framework AOP pointcut corresponding to the per clause of the * aspect. Will be the Pointcut.TRUE canonical instance in the * case of a singleton, otherwise an AspectJExpressionPointcut. */ private final Pointcut perClausePointcut; /** * Create a new AspectMetadata instance for the given aspect class. * * @param aspectClass the aspect class * @param aspectName the name of the aspect */ public AspectMetadata(Class aspectClass, String aspectName) { this.aspectName = aspectName; Class currClass = aspectClass; AjType ajType = null; while (currClass != Object.class) { AjType ajTypeToCheck = AjTypeSystem.getAjType(currClass); if (ajTypeToCheck.isAspect()) { ajType = ajTypeToCheck; break; } currClass = currClass.getSuperclass(); } if (ajType == null) { throw new IllegalArgumentException("Class '" + aspectClass.getName() + "' is not an @AspectJ aspect"); } if (ajType.getDeclarePrecedence().length > 0) { throw new IllegalArgumentException("DeclarePrecedence not presently supported in Framework AOP"); } this.aspectClass = ajType.getJavaClass(); this.ajType = ajType; switch (this.ajType.getPerClause().getKind()) { case SINGLETON -> { this.perClausePointcut = Pointcut.TRUE; } case PERTARGET, PERTHIS -> { AspectJExpressionPointcut ajexp = new AspectJExpressionPointcut(); ajexp.setLocation(aspectClass.getName()); ajexp.setExpression(findPerClause(aspectClass)); ajexp.setPointcutDeclarationScope(aspectClass); this.perClausePointcut = ajexp; } case PERTYPEWITHIN -> { // Works with a type pattern this.perClausePointcut = new ComposablePointcut(new TypePatternClassFilter(findPerClause(aspectClass))); } default -> throw new AopConfigException( "PerClause " + ajType.getPerClause().getKind() + " not supported by AOP for " + aspectClass); } } /** * Extract contents from String of form {@code pertarget(contents)}. */ private String findPerClause(Class aspectClass) { String str = aspectClass.getAnnotation(Aspect.class).value(); int beginIndex = str.indexOf('(') + 1; int endIndex = str.length() - 1; return str.substring(beginIndex, endIndex); } /** * Return AspectJ reflection information. */ public AjType getAjType() { return this.ajType; } /** * Return the aspect class. */ public Class getAspectClass() { return this.aspectClass; } /** * Return the aspect name. */ public String getAspectName() { return this.aspectName; } /** * Return a Framework pointcut expression for a singleton aspect. * (e.g. {@code Pointcut.TRUE} if it's a singleton). */ public Pointcut getPerClausePointcut() { return this.perClausePointcut; } /** * Return whether the aspect is defined as "perthis" or "pertarget". */ public boolean isPerThisOrPerTarget() { PerClauseKind kind = getAjType().getPerClause().getKind(); return (kind == PerClauseKind.PERTARGET || kind == PerClauseKind.PERTHIS); } /** * Return whether the aspect is defined as "pertypewithin". */ public boolean isPerTypeWithin() { PerClauseKind kind = getAjType().getPerClause().getKind(); return (kind == PerClauseKind.PERTYPEWITHIN); } /** * Return whether the aspect needs to be lazily instantiated. */ public boolean isLazilyInstantiated() { return (isPerThisOrPerTarget() || isPerTypeWithin()); } @Serial private void readObject(ObjectInputStream inputStream) throws IOException, ClassNotFoundException { inputStream.defaultReadObject(); this.ajType = AjTypeSystem.getAjType(this.aspectClass); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy