سؤال

My idea is to use AspectJ to catch exceptions in annotated methods and if any exceptions are thrown, the annotated method should try to run again. I have mostly followed this tutorial (http://zoftware.blogspot.cz/2008/02/using-aspectj-and-java-annotations-to_23.html) but I can't get it to work. Everything should be ok, yet it isn't. Exceptions are caught before finally and there are many exceptions thrown, not just one. Catch inside my aspect seems not to work at all. I use AspectJ 1.7.3. The code is...

Annotation:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryIfFailed {

    int maxRetries() default 5;
}

Annotated method:

@RetryIfFailed(maxRetries = 3)
private User showUser(String userName) {
    try {
        return twitter.showUser(userName);
    } catch (TwitterException e) {
        System.out.println("I am catch inside showUser");
    }
    return null;
}

Aspect:

    @Around("call(@RetryIfFailed * *..*(..))")
    public Object retryMaxRetriesTimes(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        System.out.println("Entering retryMax...");
        Method method = ((MethodSignature) thisJoinPoint.getSignature()).getMethod();
        RetryIfFailed annotation = method.getAnnotation(RetryIfFailed.class);
        int retries = annotation.maxRetries();

        Object ret = null;
        while (retries > 0) {
            try {
                System.out.println("Before proceeding... Retries=" + retries);
                ret = thisJoinPoint.proceed();
            } catch (Throwable e) {
                System.out.println("I am catched in RetryMax ");
                retries--;
                if (retries == 0) {
                    System.out.println("Exception caught. Rethrowing..." + e);
                    throw new ConnectionErrorException("Twitter service failed to establish connection", e);
                }
            } finally {
                System.out.println("Finally block..." + retries);
                if (ret != null) {
                    System.out.println("Object returned: " + ret);
                    return ret;
                }

                System.out.println("Decresing retries to" + retries);
                retries--;
                if (retries == 0) {
                    throw new ConnectionErrorException("It should not get here.");
                }
            }
        }

        //should never be reached
        return null;
    }
}

Maven configuration:

<!-- Build with AspectJ-->
    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>aspectj-maven-plugin</artifactId>
                <version>1.5</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <complianceLevel>1.7</complianceLevel>
                    <verbose>true</verbose>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                </dependencies>
            </plugin>
        </plugins>
    </build>

Output:

Entering retryMax...
Before proceeding... Retries=3
I am catch inside showUser
Finally block...3
Decresing retries to3
Before proceeding... Retries=2
I am catch inside showUser
Finally block...2
Decresing retries to2
Before proceeding... Retries=1
I am catch inside showUser
Finally block...1
Decresing retries to1
Exception in thread "main" ...<path>....ConnectionErrorException: It should not get here.
       at ...<stackTrace follows>...

Thanks for any advice :).

EDIT

As mvieghofer suggested, I never rethrow the exception. I expected @Around to catch exception inside twitter.showUser() and that was wrong. In case anybody would be interested in solution, here it is:

    @RetryIfFailed
    public static User showUser(String userName) throws ConnectionErrorException {
        try {
            return twitter.showUser(userName);
        } catch (TwitterException e) {
            throw new ConnectionErrorException(exceptionMessage, e);
        }
    }
هل كانت مفيدة؟

المحلول

There is an after throw Exception advice for AspectJ.

You could have something like this:

aspect A {
  pointcut publicCall(): call(@RetryIfFailed * *..*(..));
  after() throwing (TwitterExepction e): publicCall() {
  System.out.println("Threw an exception: " + e);
  }

}

Also you should rethrow the TwitterException inside your showUser Method. For more infos on the after() throwing advice see this link

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top