Question

I have a method that throws IOException which is called from a java timer run().Since the run() doesn't return any checked exceptions and I am using AspectJ for logging, how do I log the exception in aspectj?

This is my code:

timer = new Timer(); `

    timer.scheduleAtFixedRate(new TimerTask() {

        public void run() {

            for (OidTypes oidType : typesList) {

                try {
                    valueIncrementOperation(oidType);//------this method throws exception
                } catch (IOException e) {

                    System.out.println("Error occured inside Timer : "
                            + e.getMessage());

                    timer.cancel();
                    timer = null;
                }

            }

` I am forced to use try/catch for now. What are my options?

Was it helpful?

Solution

First you need to pack the IOException into an unchecked exception, the real exception will be the cause of the exception you catch in the advice.

The simplest is to take RuntimeException.

public void doTimerJob() {
    final Timer timer = new Timer();
    timer.scheduleAtFixedRate(new TimerTask() {
        @Override
        public void run() {
            try {
                throw new IOException("file not found");
            } catch (IOException e) {
                timer.cancel();
                throw new RuntimeException(e);
            }
        }
    }, new Date(), 2000);
}

Then you could try the following:

Create a point cut for TimerTask#run

pointcut timerTaskRun() : execution(public * java.util.TimerTask.run(..) );

and an advice for after throwing a RuntimeException

after() throwing(RuntimeExceptione) : timerTaskRun() {
    System.out.println("log and rethrow " + e.getCause().getMessage());
}

This will re-throw the exception after logging it.

If you want to log and swallow the exception you could write an around advice

Object around() : timerTaskRun() {
    Object o;
    try {
        o = proceed();   
    } catch(RuntimeException e) {
        System.out.println("log and swallow " + e.getCause().getMessage());
        o = null;
    }
    return o;
}

Note that you should only have only one of the advices, either after throwing or around not both.

But you may not want to advice all TimerTask#run calls along with all RuntimeExceptions. In this case you should create own types which you should use in the point cut and the advices.

"Unchecked" IOException

public class IOExceptionUnchecked extends RuntimeException {
    private static final long serialVersionUID = 1L;
    public IOExceptionUnchecked(IOException e) {
        super(e);
    }
}

Custom TimerTask

public class MyTimerTask extends TimerTask  {
    Timer owner = null; 
    public MyTimerTask(Timer timer) {this.owner = timer;}
    @Override
    public void run() {
        try {
            throw new IOException("file not found");
        } catch (IOException e) {
            owner.cancel();
            throw new IOExceptionUnchecked(e);
        }
    }
}

Point cut

pointcut timerTaskRun() : execution(public * com.example.MyTimerTask.run(..) );

after throwing advice:

after() throwing(IOExceptionUnchecked e) : timerTaskRun() {
    System.out.println("log and rethrow " + e.getCause().getMessage());
}

Or around advice

Object around() : timerTaskRun() {
    Object o;
    try {
        o = proceed();   
    } catch(IOExceptionUnchecked e) {
        System.out.println("log and swallow " + e.getCause().getMessage());
        o = null;
    }
    return o;
}

OTHER TIPS

You cannot get rid of the try/catch block because IOException is a checked exception and TimerTask#run is declared not to throw any checked Exception. Also you have additional logic in the catch block to cancel the timer.

The nearest thing you can you is wrap the IOException to a RuntimeException and re-throw it.

   catch(IOException){
        timer.cancel();
        throw new RuntimeException(e);
    }

Even by doing so, the exception and stack trace would not be logged by AspectJ. To do so, you need to use a container(like Spring) to create the TimerTask instance and wrap it with AspectJ interceptor.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top