JJ *_*kar 6 java aop hibernate spring-aop spring-data-jpa
我希望能够编写一个方面来检测我何时在我的一个org.mypackage
类中投射某些东西。
package org.mypackage;
class Foo {
public static void main(String[] args) {
Bar casted = (Bar) args[0]; // want to detect this casting action!
}
}
Run Code Online (Sandbox Code Playgroud)
你如何编写一个切入点来表达强制转换操作,不仅仅是为了Foo
类,而是对于org.mypackage
.
背景:所以 Hibernate 5 + Spring Data JPA 需要通过继承来转换实体:
if (isInstanceOfMyEntity(someEntity)) {
// formerly, this was sufficient:
// MyEntity myEntity = (MyEntity) someEntity;
// now, this is required *everywhere* it is casted:
MyEntity myEntity = (MyEntity) Hibernate.unproxy(someEntity);
...
}
Run Code Online (Sandbox Code Playgroud)
...在大型代码库中,考虑这点很可怕,因为这可能会破坏很多地方。因此,如果可以编写一个切面/切入点来至少检测它,那么我们至少可以记录它并确定测试中需要解决问题的位置。
@Vlad-Mihalcea在这个问题如何将 Hibernate 代理转换为真实的实体对象中推荐了这种技术。
对于 Spring AOP 和 AspectJ,答案是:您不能拦截强制转换。没有像这样细粒度的切入点。
背景:这也没有意义,因为某些强制转换甚至不存在于字节码中,因为编译器将它们优化掉了。其他的checkcast
在字节码中用a表示。看这个例子:
package de.scrum_master.stackoverflow.q58984334;
public class Dummy {
public void foo() {
int i = (int) 42L;
System.out.println(i);
}
public void bar() {
Base base = new Sub();
Sub sub = (Sub) base;
System.out.println(sub);
}
static class Base {}
static class Sub extends Base {}
}
Run Code Online (Sandbox Code Playgroud)
如果你通过 反汇编它javap -c Dummy.class
,你会得到:
Compiled from "Dummy.java"
public class de.scrum_master.stackoverflow.q58984334.Dummy {
public de.scrum_master.stackoverflow.q58984334.Dummy();
Code:
0: aload_0
1: invokespecial #8 // Method java/lang/Object."<init>":()V
4: return
public void foo();
Code:
0: bipush 42
2: istore_1
3: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
6: iload_1
7: invokevirtual #21 // Method java/io/PrintStream.println:(I)V
10: return
public void bar();
Code:
0: new #30 // class de/scrum_master/stackoverflow/q58984334/Dummy$Sub
3: dup
4: invokespecial #32 // Method de/scrum_master/stackoverflow/q58984334/Dummy$Sub."<init>":()V
7: astore_1
8: aload_1
9: checkcast #30 // class de/scrum_master/stackoverflow/q58984334/Dummy$Sub
12: astore_2
13: getstatic #15 // Field java/lang/System.out:Ljava/io/PrintStream;
16: aload_2
17: invokevirtual #33 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
20: return
}
Run Code Online (Sandbox Code Playgroud)
看?即使需要在源代码中进行编译,从long
to的强制转换int
也不存在。那么如何拦截呢?很抱歉这次深入探讨,实际答案在第一段中。
更新:
鉴于您无法确定强制转换是否存在于字节码中,您可以做的是编写一个简单的测试,扫描您的源代码并在每个 Maven 或 Gradle 构建期间编写报告。
或者,如果您想变得更复杂,您可以编写一个编译器插件,该插件将检查表示已解析源代码的 AST(抽象语法树),然后在发现需要报告的内容时发出编译器警告。
使用 AspectJ(不是 Spring AOP),您可以拦截对 的调用Hibernate.unproxy()
,但是您需要检测的是这些调用是否缺失,因此您无法为甚至不存在的内容编写切入点。
归档时间: |
|
查看次数: |
122 次 |
最近记录: |