How to add control over invoking of methods in existing sub classes without modifying the sub classes?

class, java, methods

Solution

You want to use `@Around` advice from AspectJ and do something like this:

// Let subClass instances run normally...
cec.setActive(true);
letThemDoSomething("BEFORE", sbc1, sbc2, sbc3);

// Now change existing scenario...
cec.setActive(false);
letThemDoSomething("AFTER", sbc1, sbc2, sbc3);

This will output:

BEFORE ======
SubClass1: doSomething() called.
SubClass2: doSomething() called.
SubClass3: doSomething() called.

AFTER ======
Blocking instance<1> method: my.first.spring.aop.aspectj.SubClassN#doSomething([]) !!
Blocking instance<2> method: my.first.spring.aop.aspectj.SubClassN#doSomething([]) !!
Blocking instance<3> method: my.first.spring.aop.aspectj.SubClassN#doSomething([]) !!

In the following lines, I'll describe how to make this happen with the annotation. I will also use Spring here. It helps making the configuration quickier and easier.

1- Configuration

Tools and dependencies

Java 7, AspectJ 1.7.4, Spring 4.0.2

Project structure

pom.xml

<project ...>

  <properties>
     <maven.compiler.source>1.7</maven.compiler.source>
     <maven.compiler.target>1.7</maven.compiler.target> 

     <spring.version>4.0.2.RELEASE</spring.version>
     <aspectj.version>1.7.4</aspectj.version>
  </properties>

  <dependencies>
    <!-- Spring -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>${spring.version}</version>
    </dependency>

    <!-- AspectJ -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>${aspectj.version}</version>
    </dependency>

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>${aspectj.version}</version>
    </dependency>
  </dependencies>

</project>

2 - Existing code

BaseClass.java

public class BaseClass {
    public void doSomething() {

    }

    public void say(String msg) {
         System.out.println(msg);
    }
}    

SubClassN.java

public class SubClassN extends BaseClass {
    private Integer index;

    public SubClassN(Integer index) {
        this.index = index;
    }

    @Override
    public void doSomething() {
        say("SubClass" + index + ": doSomething() called.");
    }

    public Integer getIndex() {
        return index;
    }
}

3 - Change existing code (without breaking anything...)

Here comes AspectJ and its @Around advice. We'll first ask AsjectJ to call a particular method when any `doSomething` method is invoked. `doSomething` can be anywhere in the `BaseClass` or in any of its child class.

This particular method is called `changeExistingScenario`. It can have any name. The important here is the annotation placed on it.

A word about the @Around value:

execution(* my.first.spring.aop.aspectj.BaseClass.doSomething(..))

This expression simply indicates the method signature pattern we want to intercept. It will intercept any doSomething method in BaseClass or child class no matter how many parameters, return type and access modifier.

For more details see: http://guptavikas.wordpress.com/2010/04/15/aspectj-pointcut-expressions/

ChangeExistingCode.java

@Aspect // Mark ChangeExistingCode as the class for modifying the code 
@Component
public class ChangeExistingCode {
    private boolean active;

    public void setActive(boolean active) {
        this.active = active;
    }

    /**
     *
     * This method will be called by AspectJ anytime a `doSomething` method is called.
     *
     * This will give us a chance to decide whether the `doSomething` method should
     * be called or not.
     *
     */
    @Around("execution(* my.first.spring.aop.aspectj.BaseClass.doSomething(..))")
    public void changeExistingScenario(ProceedingJoinPoint joinPoint) throws Throwable {
        // Is active ?
        if (active) { // Yes, let doSomething() run as usual
            joinPoint.proceed();
        } else {// No, block doSomething() invokation
            Signature s = joinPoint.getSignature();

            System.out.format( //
                    "Blocking instance<%d> method: %s#%s(%s) !!\n", //
                    ((SubClassN)joinPoint.getTarget()).getIndex(), //
                    s.getDeclaringTypeName(), //
                    s.getName(), //
                    Arrays.toString(joinPoint.getArgs()) //
                    );
        }
    }
}

4- Let's all the magic appear...

Main.java

@Configuration // Mark the Main class as the class where Spring will find its configuration
@ComponentScan // Ask Spring to look for other components within the Main class package
@EnableAspectJAutoProxy // Let Spring auto configure AspectJ aspects for us...
public class Main {

    private static int subClassCounter;

    public static void main(String[] args) {
        subClassCounter=0;

        GenericApplicationContext  context = new AnnotationConfigApplicationContext(Main.class);

        SubClassN sbc1 = context.getBean(SubClassN.class);
        SubClassN sbc2 = context.getBean(SubClassN.class);
        SubClassN sbc3 = context.getBean(SubClassN.class);

        ChangeExistingCode cec = context.getBean(ChangeExistingCode.class);

        // Let subClass instances run normally...
        cec.setActive(true);
        letThemDoSomething("BEFORE", sbc1, sbc2, sbc3);

        // Now change existing scenario...
        cec.setActive(false);
        letThemDoSomething("AFTER", sbc1, sbc2, sbc3);

        context.close();
    }

    private static void letThemDoSomething(String prefix, SubClassN... existingClasses) {
        System.out.format("%s ======\n", prefix);
        for (SubClassN subClassInstance : existingClasses) {
            subClassInstance.doSomething();
        }
        System.out.println();
    }

    @Bean // Tell Spring to use this method for creating SubClassN instances
    @Scope(BeanDefinition.SCOPE_PROTOTYPE) // Scope prototype force creation of multiple instances
    private static SubClassN buildSubClassN() {
        subClassCounter++;
        return new SubClassN(subClassCounter);
    }
}

Output

BEFORE ======
SubClass1: doSomething() called.
SubClass2: doSomething() called.
SubClass3: doSomething() called.

AFTER ======
Blocking instance<1> method: my.first.spring.aop.aspectj.SubClassN#doSomething([]) !!
Blocking instance<2> method: my.first.spring.aop.aspectj.SubClassN#doSomething([]) !!
Blocking instance<3> method: my.first.spring.aop.aspectj.SubClassN#doSomething([]) !!

5- References

Download full code: http://www.filedropper.com/advicearoundsample

AspectJ official site

- @Around javadoc

- @Aspect javadoc

Spring official site

- @Bean javadoc

- @Component javadoc

- @ComponentScan javadoc

- @Configuration javadoc

- @EnableAspectJAutoProxy javadoc

Other useful resources that helped writing this answer

- AspectJ Pointcut Expressions

- Mkyong - Spring AOP + AspectJ annotation example

Problem

I have some `BaseClass` with some method `void doSomething()`. There are different ways to `foSomething` and they are implemented by `SubClass1`, `SubClass2` and `SubClass3`. Now I want to add a `Boolean active` property to the `BaseClass` so that when `doSomething` is called on an instance it will just return without doing anything. I know I can code the `BaseClass` to have `doSomething()` that looks something like: ``` Void doSomething(){ if (this.getActive()) actuallyDoSomething(); } ``` And then `@Override actuallyDoSomething()` instead of `@Override doSomething()` in the subclasses. but it feels wrong... in the sense that It has already been agreed that the subclasses should provide an implementation for `doSomething()` and they are not aware of `actuallyDoSomething()`. I also can have each sub class add an `if (!this.getActive()) return;` at the beginning of its implementation of `doSomething()` but this also seems wrong as its common functionality that I would prefer to keep common. What is the common/best practice way to do this? Can it be done without changing the sub classes? Update The focus of the Q is not about the right way to design such functionality (which is quite simple), but on how such functionality can be added to an existing scenario without breaking anything. `active` would be true by default, but it is desired that on any instance of any the said sub classes if someone would call `setActive(false)` then it will become inactive and consecutive calls to `.doSomething()` will not do anything...

Original source