Reputation: 2454
I have a java file which has a method that has been coded like this
public void testMethod() {
ClassA objA = new ClassA("objA");
objA.someMethod();
ClassA objB = new ClassA("objB");
objB.someMethod();
ClassA objC = new ClassA("objC");
objC.someMethod();
}
This file has been given to me and I have the liberty of a) changing this file manually and adding code to it b) changing this file automatically using a Java Parser. My aim here is to control the execution of someMethod()
. For instance, I want to inject a Configuration
object into the class, which will specify which object's someMethod()
should be invoked. So, something like this:
Configuration config;
public void testMethod() {
ClassA objA = new ClassA("objA");
if(config.shouldExecuteFor(objA))
objA.someMethod();
ClassA objB = new ClassA("objB");
if(config.shouldExecuteFor(objB))
objB.someMethod();
ClassA objC = new ClassA("objC");
if(config.shouldExecuteFor(objC))
objC.someMethod();
}
The if conditions that are shown above, could be
I am inclined towards (b). I am not sure if I am solving this problem correctly or not, or if there is something that I can do to solve it in a simpler manner by leveraging annotations/aspects (as in 'c' above).
I would appreciate any input in solving this problem.
Upvotes: 0
Views: 740
Reputation: 1982
Here is an example using Spring AOP with AspectJ. I created a dummy configuration class MyConfiguration
which simply returns an alternating boolean when calling its shouldExecuteFor()
method to have some kind of test behavior. The ConfiguredCallAspect
uses a call pointcut, which only works in Spring AOP when load time weaving is used. That is why I use XML configuration via applicationContext.xml
and not annotations. The -Xreweavable
option in aop.xml
is also important for that, as well as the two -javaagent
arguments passed to the JVM. This became rather complex but I think it does the job you were asking for.
src/experiments/stackoverflow/aspectj/ClassA.java
package experiments.stackoverflow.aspectj;
public class ClassA {
private String name;
public ClassA(String name) {
this.name = name;
}
public void someMethod() {
System.out.println("someMethod(\"" + name + "\") called on " + this);
}
}
src/experiments/stackoverflow/aspectj/App.java
package experiments.stackoverflow.aspectj;
public class App {
public void run() {
ClassA object1 = new ClassA("obj1");
object1.someMethod();
ClassA object2 = new ClassA("obj2");
object2.someMethod();
ClassA object3 = new ClassA("obj3");
object3.someMethod();
ClassA object4 = new ClassA("obj4");
object4.someMethod();
ClassA object5 = new ClassA("obj5");
object5.someMethod();
}
}
src/experiments/stackoverflow/aspectj/ConfiguredCallAspect.java
package experiments.stackoverflow.aspectj;
import javax.inject.Inject;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.beans.factory.annotation.Configurable;
@Aspect
@Configurable
public class ConfiguredCallAspect {
private MyConfiguration config;
public MyConfiguration getConfig() {
return config;
}
@Inject
public void setConfig(MyConfiguration config) {
this.config = config;
}
/**
* Pointcut for all calls to ClassA.someMethod().
*/
@Around("call(* ClassA.someMethod())")
public void conditionalExecutionOfSomeMethod(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("Aspect start");
if (config.shouldExecuteFor(joinPoint.getTarget())) {
joinPoint.proceed();
}
System.out.println("Aspect end");
}
}
src/experiments/stackoverflow/aspectj/Main.java
package experiments.stackoverflow.aspectj;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
context.getBean(App.class).run();
}
}
src/experiments/stackoverflow/aspectj/MyConfiguration.java
package experiments.stackoverflow.aspectj;
public class MyConfiguration {
private boolean executionTrigger = false;
public boolean shouldExecuteFor(Object anObject) {
executionTrigger = !executionTrigger;
System.out.println("should execute " + anObject + "? " + executionTrigger);
return executionTrigger;
}
}
src/META-INF/aop.xml
<!DOCTYPE aspectj PUBLIC
"-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>
<weaver
options="-Xreweavable">
<include within="experiments.stackoverflow.aspectj..*" />
</weaver>
<aspects>
<aspect name="experiments.stackoverflow.aspectj.ConfiguredCallAspect"/>
</aspects>
</aspectj>
src/applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:load-time-weaver />
<bean id="configuredCallAspect" class="experiments.stackoverflow.aspectj.ConfiguredCallAspect" factory-method="aspectOf">
<property name="config"><ref bean="config"/></property>
</bean>
<bean id="config" class="experiments.stackoverflow.aspectj.MyConfiguration" />
<bean id="app" class="experiments.stackoverflow.aspectj.App" />
</beans>
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>experiments</groupId>
<artifactId>experiments</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<org.springframework.version>4.2.1.RELEASE</org.springframework.version>
<aspectj.version>1.8.7</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${aspectj.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-instrument</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Start the program using:
java -javaagent:<path-to>/aspectjweaver-1.8.7.jar -javaagent:<path-to>/spring-instrument-4.2.1.RELEASE.jar experiments.stackoverflow.aspectj.Main
Produced output:
Aspect start
should execute experiments.stackoverflow.aspectj.ClassA@a0bf272? true
someMethod("obj1") called on experiments.stackoverflow.aspectj.ClassA@a0bf272
Aspect end
Aspect start
should execute experiments.stackoverflow.aspectj.ClassA@4a89ef44? false
Aspect end
Aspect start
should execute experiments.stackoverflow.aspectj.ClassA@310a7859? true
someMethod("obj3") called on experiments.stackoverflow.aspectj.ClassA@310a7859
Aspect end
Aspect start
should execute experiments.stackoverflow.aspectj.ClassA@1cbc1dde? false
Aspect end
Aspect start
should execute experiments.stackoverflow.aspectj.ClassA@4971f459? true
someMethod("obj5") called on experiments.stackoverflow.aspectj.ClassA@4971f459
Aspect end
Upvotes: 1