How to catch and suppress an Exception Thrown from a Java Class using Aspectj

401 Views Asked by At

I want to handle this exception thrown from Circle.getArea() method using Aspectj.

Shape.java

    package Shapes;
    
    public class Circle {
        private double radius;
        public Circle(double radius) {
               this.radius = radius;
        }
        public double getPerimeter(){
               return 2 * Math.PI * this.radius;
        }
        public double getArea(){
            return Math.PI * this.radius * this.radius;
        }
    }

Rectangle.java


    package Shapes;
    
    public class Rectangle {
        private double width, height;
        public Rectangle(double width, double height) {
             this.width = width;
             this.height = height;
        }
        public double getPerimeter() {
               return 2 * (this.width + this.height);
        }
        public double getArea() {
               return this.width * this.height;
        }
    }

Circle.java


    package Shapes;
    
    public class Circle {
        private double radius;
        public Circle(double radius) {
            this.radius = radius;
        }
        public double getPerimeter() {
            return 2 * Math.PI * this.radius;
        }
        public double getArea() {
            throw new RuntimeException("Oops, I don't know how to calculate this :(");
        }
    }

Main.java


    package Shapes;
    
    public class Main {
    
        public static void main(String[] args) {
            try {
                Shape s;
                s = (Shape) new Rectangle(2, 10);
                System.out.println("The area of " + s + " is " + s.getArea());
                
                s = (Shape) new Rectangle(-2, 10);
                System.out.println("The perimeter of " + s +" is " + s.getPerimeter());
                
                s = (Shape) new Circle(-2);
                System.out.println("The perimeter of " + s +" is " + s.getPerimeter());
                
                s = (Shape) new Circle(2);
                System.out.println("The area of " + s + " is " + s.getArea());
                }
                catch(Exception e) {
                    System.out.println("Error: " + e.getMessage());
                }
        }
    }

Resolve.aj


    package Shapes;
    
    privileged public aspect Resolve {
        declare parents: Rectangle implements Shape;
        declare parents: Circle implements Shape;
        
        public String Rectangle.getName(){
            return "Rectangle";
        }
        
        public String Circle.getName(){
            return "Circle";
        }
        
        public String Rectangle.toString(){
            return this.getName()+"("+this.width+","+this.height+")";
        }
        public String Circle.toString(){
            return this.getName()+"("+this.radius+")";
        }
        
    
        after() throwing(RuntimeException e) : execution(* Circle.*()){
            handleException();
        }   
    
        protected void handleException()
        {
            System.out.println("Error detected");
        }
    }

The current output is:

The area of Rectangle(2.0,10.0) is 20.0

The perimeter of Rectangle(-2.0,10.0) is 16.0

The perimeter of Circle(-2.0) is -12.566370614359172

Error detected

Error: Oops, I don't know how to calculate this :(

I want to avoid printing "Error: Oops, I don't know how to calculate this :(", and I need to get the real area of the circle object at the end. But, I cannot change any .java file. All changes should be using Resolve.aj file.

1

There are 1 best solutions below

0
On BEST ANSWER

You need to use the around advice instead of the after:

     Object around () : execution(* Circle.*()){
         try {
              return proceed();
         } 
         catch(Exception e) 
         {
            handleException();
         }
         return null;
    }   

Code output:

The area of Rectangle(2.0,10.0) is 20.0
The perimeter of Rectangle(-2.0,10.0) is 16.0
The perimeter of Circle(-2.0) is -12.566370614359172
Error detected
The area of Circle(2.0) is 0.0

Why are we using the around advice instead of the after?

Very informally, an around advice intercepts a given joinpoint, and can inject new behavior before, after, and instead of that joinpoint. The proceed is a special feature that allows the around advice to continue the execution of the joinpoint.

From the types of advice supported by AspectJ (i.e., before, after, and around), the around advice is the only one allowed to return a value and/or use the proceed. This makes it possible for an around advice to execute several times the same joinpoint, or not executed it at all. Furthermore, you can even execute the intercepted joinpoint with a different context (e.g., change the value of the method arguments).

More information about how the advice and proceed works can be found on this SO Thread.

Our around advice will intercept all the execution joinpoint of the methods from the class Circle, and will handle accordingly the exceptions thrown by those methods.