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

org.springframework.aop.aspectj.RuntimeTestWalker Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * Copyright 2002-2006 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.aspectj;

import java.lang.reflect.Field;

import org.aspectj.weaver.ResolvedType;
import org.aspectj.weaver.ast.And;
import org.aspectj.weaver.ast.Call;
import org.aspectj.weaver.ast.FieldGetCall;
import org.aspectj.weaver.ast.HasAnnotation;
import org.aspectj.weaver.ast.ITestVisitor;
import org.aspectj.weaver.ast.Instanceof;
import org.aspectj.weaver.ast.Literal;
import org.aspectj.weaver.ast.Not;
import org.aspectj.weaver.ast.Or;
import org.aspectj.weaver.ast.Test;
import org.aspectj.weaver.internal.tools.MatchingContextBasedTest;
import org.aspectj.weaver.reflect.ReflectionVar;
import org.aspectj.weaver.reflect.ReflectionWorld;
import org.aspectj.weaver.reflect.ShadowMatchImpl;
import org.aspectj.weaver.tools.ShadowMatch;

/**
 * 

This class encapsulates some AspectJ internal knowledge that should be * pushed back into the AspectJ project in a future release. * *

It relies on implementation specific knowledge in AspectJ to break * encapsulation and do something AspectJ was not designed to do :- query * the types of runtime tests that will be performed. The code here should * migrate to ShadowMatch.getVariablesInvolvedInRuntimeTest() or some similar * operation. * *

See https://bugs.eclipse.org/bugs/show_bug.cgi?id=151593 * * @author Adrian Colyer * @author Ramnivas Laddad * @since 2.0 */ public class RuntimeTestWalker { private Test runtimeTest; public RuntimeTestWalker(ShadowMatch shadowMatch) { ShadowMatchImpl shadowMatchImplementation = (ShadowMatchImpl) shadowMatch; try { Field testField = shadowMatchImplementation.getClass().getDeclaredField("residualTest"); testField.setAccessible(true); this.runtimeTest = (Test) testField.get(shadowMatch); } catch(NoSuchFieldException noSuchFieldEx) { throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " + "on the classpath is incompatible with this version of Spring:- expected field " + "'runtimeTest' is not present on ShadowMatchImpl class"); } catch (IllegalAccessException illegalAccessEx) { // famous last words... but I don't see how this can happen given the // setAccessible call above throw new IllegalStateException("Unable to access ShadowMatchImpl.runtimeTest field."); } } /** * If the test uses any of the this, target, at_this, at_target, and at_annotation vars, * then it tests subtype sensitive vars. */ public boolean testsSubtypeSensitiveVars() { return new SubtypeSensitiveVarTypeTestVisitor().testsSubtypeSensitiveVars(this.runtimeTest); } public boolean testThisInstanceOfResidue(Object thiz) { return new ThisInstanceOfResidueTestVisitor(thiz).thisInstanceOfMatches(this.runtimeTest); } private static class TestVisitorAdapter implements ITestVisitor { protected static final int THIS_VAR = 0; protected static final int AT_THIS_VAR = 3; protected static final int AT_TARGET_VAR = 4; protected static final int AT_ANNOTATION_VAR = 8; public void visit(And e) { e.getLeft().accept(this); e.getRight().accept(this); } public void visit(Or e) { e.getLeft().accept(this); e.getRight().accept(this); } public void visit(Not e) { e.getBody().accept(this); } public void visit(Instanceof i) { } public void visit(Literal literal) { } public void visit(Call call) { } public void visit(FieldGetCall fieldGetCall) { } public void visit(HasAnnotation hasAnnotation) { } public void visit(MatchingContextBasedTest matchingContextTest) { } protected int getVarType(ReflectionVar v) { try { Field varTypeField = ReflectionVar.class.getDeclaredField("varType"); varTypeField.setAccessible(true); Integer varTypeValue = (Integer) varTypeField.get(v); int varType = varTypeValue.intValue(); return varType; } catch(NoSuchFieldException noSuchFieldEx) { throw new IllegalStateException("the version of aspectjtools.jar / aspectjweaver.jar " + "on the classpath is incompatible with this version of Spring:- expected field " + "'varType' is not present on ReflectionVar class"); } catch(IllegalAccessException illegalAccessEx) { // famous last words... but I don't see how this can happen given the setAccessible call // above throw new IllegalStateException("Unable to access ReflectionVar.varType field."); } } } /** * * Check if residue of this(TYPE) kind. See SPR-2979 for more details. * */ private static class ThisInstanceOfResidueTestVisitor extends TestVisitorAdapter { private Object thiz; private boolean matches = true; public ThisInstanceOfResidueTestVisitor(Object thiz) { this.thiz = thiz; } public boolean thisInstanceOfMatches(Test test) { test.accept(this); return matches; } public void visit(Instanceof i) { ResolvedType type = (ResolvedType)i.getType(); int varType = getVarType((ReflectionVar)i.getVar()); // We are concerned only about this() pointcut // TODO: Optimization: Process only if this() specifies a type and not identifier if(varType != THIS_VAR) { return; } try { Class typeClass = Class.forName(type.getName()); // Don't use ReflectionType.isAssignableFrom() as it won't be aware of (Spring) mixins if(!typeClass.isAssignableFrom(thiz.getClass())) { matches = false; } } catch (ClassNotFoundException ex) { matches = false; } } } private static class SubtypeSensitiveVarTypeTestVisitor extends TestVisitorAdapter { private final Object thisObj = new Object(); private final Object targetObj = new Object(); private final Object[] argsObjs = new Object[0]; private boolean testsSubtypeSensitiveVars = false; public boolean testsSubtypeSensitiveVars(Test aTest) { aTest.accept(this); return this.testsSubtypeSensitiveVars; } public void visit(Instanceof i) { ReflectionVar v = (ReflectionVar) i.getVar(); Object varUnderTest = v.getBindingAtJoinPoint(thisObj,targetObj,argsObjs); if ((varUnderTest == thisObj) || (varUnderTest == targetObj)) { this.testsSubtypeSensitiveVars = true; } } public void visit(HasAnnotation hasAnn) { // if you thought things were bad before, now we sink to new levels // of horror... ReflectionVar v = (ReflectionVar) hasAnn.getVar(); int varType = getVarType(v); if ((varType == AT_THIS_VAR) || (varType == AT_TARGET_VAR) || (varType == AT_ANNOTATION_VAR)) { this.testsSubtypeSensitiveVars = true; } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy