AspectJ:尝试拦截对象创建时的ClassCastException

时间:2014-08-09 08:08:40

标签: aspectj

我试图拦截遗留代码中的对象创建以返回另一个对象。

我的示例代码:

public class ObjectCreationTest {

interface A {
    String say();
}

public static class MyImpl implements A {

    @Override
    public String say() {
        return "MyImpl";
    }
}

public static class YourImpl implements A {

    @Override
    public String say() {
        return "YourImpl";
    }
}

public static void main(String[] args) {
    A obj = new MyImpl();
    System.out.println(obj.getClass());
    System.out.println(obj.say());

}
}

@Aspect
public class MyAspect {

@Around(value = "call(com.leon.test.ObjectCreationTest$MyImpl.new(..))")
public Object initAdvice(ProceedingJoinPoint pjp) throws Throwable {
    return new ObjectCreationTest.YourImpl();
}

}

然而,我得到了:

Exception in thread "main" java.lang.ClassCastException: com.leon.test.ObjectCreationTest$YourImpl cannot be cast to com.leon.test.ObjectCreationTest$MyImpl
    at com.leon.test.ObjectCreationTest.main(ObjectCreationTest.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

只有当我将YourImpl更改为从MyImpl扩展时,它才有效。 (但这不是我的预期)

只是想知道有什么不对或者不可行吗?

由于

2 个答案:

答案 0 :(得分:0)

似乎不可能我害怕。在对象创建和赋值行A obj = new MyImpl();右侧之间似乎发生了强制转换,因为返回null可以正常工作。这也可以解释为什么扩展修复了问题,因为右侧仍然会有正确的类型(MyImpl)。

这意味着通过隐藏构造函数并提供静态实例化方法来存在一种解决方法,该方法返回 Interface 类型的对象作为实例化MyImpl的唯一方法。这最终看起来相当粗糙:

public class ObjectCreationTest {

    public static void main(final String[] args) {
        A obj = MyImpl.instance();
        System.out.println(obj.getClass());
        System.out.println(obj.say());
    }
}

public class MyImpl implements A {

    public static A instance() {
        return new MyImpl();
    }

    private MyImpl() {
    }   

    @Override
    public String say() {
        return "MyImpl";
    }
}

然后你让你的方面捕获对instance() - 方法的调用:

@Aspect
public class MyAspect {
    @Around(value = "call(A com.oneandone.MyImpl.instance(..))")
    public Object initAdvice(final ProceedingJoinPoint pjp) throws Throwable {
        return new YourImpl();
    }
}

不确定这是否仍适用于您的用例,但我认为这是您最初尝试的最接近的工作。

答案 1 :(得分:0)

你想要什么不适用于兄弟类,但如果你可以选择让YourImpl成为MyImpl的子类,那么它可以工作:

驱动程序应用程序:

package de.scrum_master.app;

public class ObjectCreationTest {
    public interface A {
        String say();
    }

    public static class MyImpl implements A {
        @Override
        public String say() {
            return "MyImpl";
        }
    }

    public static class YourImpl extends MyImpl {
        @Override
        public String say() {
            return "YourImpl";
        }
    }

    public static void main(String[] args) {
        A obj = new MyImpl();
        System.out.println(obj.getClass());
        System.out.println(obj.say());
    }
}

<强>方面:

package de.scrum_master.aspect;

import de.scrum_master.app.ObjectCreationTest.*;

public aspect MyAspect {
    Object around() : !within(MyAspect) && call(A+.new(..)) {
        System.out.println(thisJoinPoint);
        return new YourImpl();
    }
}

控制台输出:

call(de.scrum_master.app.ObjectCreationTest.MyImpl())
class de.scrum_master.app.ObjectCreationTest$YourImpl
YourImpl