目标:从我的任何static filter()
课程中调用班级的@Entity
方法。返回List<Object
。获得正确的类调用者类型。
例如,当我从filter()
类调用User
时,我希望将User
作为调用者类(而不是拥有原始静态方法的类)。
此filter()
方法位于ORMEntity
:
public static List<Object> filter(){
System.out.println("Called filter method!");
return Collections.emptyList();
}
我写了这个方面:
public privileged aspect OrmAspect {
//Extends ORMEntity when class marked with @Entity
declare parents : (@Entity *) extends ORMEntity;
//Getting filter() calls from anywhere
//This pointing to ORMEntity.filter()
pointcut staticFilter() : call(* *.filter());
before() : staticFilter(){
System.out.println(">>"+thisJoinPoint);
}
然后我可以从我的主要方法中编码:
User.filter();
User是一个带有@Entity
注释的简单bean。
这就是这样的:
filter()
类中的User
方法。确定。filter()
的切入点仅在ORMEntity.filter()
上,即使User extends ORMEntity
(然后是filter()
方法)也是如此。不行。 filter()
加入点之前的输出:
System.out.println(">>"+thisJoinPoint.getSignature().getDeclaringType());
ORMEntity
而不是我期望的User
。
如何让User
类继承static filter()
方法?
或者喜欢使用AspectJ在declare parent
上进行切入点?
答案 0 :(得分:0)
似乎不可能。
需要隐藏User类中的静态ORMEntity filter()方法。 但静态方法在编译时解决。
我看到的唯一解决方案是在.java文件中生成静态filter()方法,就像lombok可以用getter / setter一样。
答案 1 :(得分:0)
正如我们在您自己的回答中所讨论的那样,我怀疑您的应用程序设计是否真的有意义,但是对于它的价值,我已经使用AspectJ's annotation processing capability introduced in version 1.8.2为您准备了一个解决方案。这个解决方案是我在another StackOverflow answer中为更复杂的案例描述的简化版本。
这是我的Eclipse布局,包含两个源文件夹和一个执行两阶段编译过程的Windows批处理文件,
以下是我的目录布局的屏幕截图:
如您所见,Eclipse无法直接编译类Application
,您确实需要使用批处理文件。
标记注释:
注意,此类必须存储在 src_apt 中才能显示
稍后注释处理器EntityProcessor
。
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {}
两个带注释的样本实体:
package de.scrum_master.app;
@Entity
public class User {}
package de.scrum_master.app;
@Entity
public class Group {}
驱动程序应用程序:
此应用程序依赖于APT在实际查看所使用的静态方法之前完成其工作。
package de.scrum_master.app;
public class Application {
public static void main(String[] args) {
User.filter();
Group.filter();
}
}
Aspect打印方法签名:
这是原始方面的简化版本,只有打印方法签名,不会声明任何父级或静态方法。这只是为了以后获得更好的日志输出:
package de.scrum_master.aspect;
public aspect LogAspect {
pointcut staticFilter() :
call(public static * filter());
before() : staticFilter(){
System.out.println(thisJoinPoint);
}
}
注释处理器:
此注释处理器搜索使用@Entity
注释的类,并创建一个方面,为每个类引入静态方法filter()
。
package de.scrum_master.app;
import java.io.*;
import java.util.*;
import javax.tools.*;
import javax.annotation.processing.*;
import javax.lang.model.*;
import javax.lang.model.element.*;
@SupportedAnnotationTypes(value = { "*" })
@SupportedSourceVersion(SourceVersion.RELEASE_8)
public class EntityProcessor extends AbstractProcessor {
private Filer filer;
@Override
public void init(ProcessingEnvironment env) {
filer = env.getFiler();
}
@Override
public boolean process(Set<? extends TypeElement> elements, RoundEnvironment env) {
env.getElementsAnnotatedWith(Entity.class).stream()
.filter(annotatedClass -> annotatedClass.getKind() == ElementKind.CLASS)
.forEach(annotatedClass -> {
String packageName = annotatedClass.getEnclosingElement().toString().substring(8);
String className = annotatedClass.getSimpleName().toString();
String aspectName = "ORMAspect_" + className;
String aspectSource = createAspectSource(packageName, className,aspectName);
writeAspectSourceToDisk(packageName, aspectName, aspectSource);
});
return true;
}
private String createAspectSource(String packageName, String className, String aspectName) {
StringBuilder aspectSource = new StringBuilder()
.append("package " + packageName + ";\n\n")
.append("import java.util.Collections;\n")
.append("import java.util.List;\n\n")
.append("public aspect " + aspectName + " {\n")
.append(" public static List<Object> " + className + ".filter() {\n")
.append(" System.out.println(\"Called filter method!\");\n")
.append(" return Collections.emptyList();\n")
.append(" }\n")
.append("}\n");
return aspectSource.toString();
}
private void writeAspectSourceToDisk(String packageName, String aspectName, String aspectSource) {
try {
JavaFileObject file = filer.createSourceFile(packageName + "." + aspectName);
file.openWriter().append(aspectSource).close();
System.out.println("Generated aspect " + packageName + "." + aspectName);
} catch (IOException ioe) {
// Message "already created" can appear if processor runs more than once
if (!ioe.getMessage().contains("already created"))
ioe.printStackTrace();
}
}
}
注释处理器的服务描述符:
这是 META-INF / services / javax.annotation.processing.Processor 的内容:
de.scrum_master.app.EntityProcessor
执行两阶段编译的批处理文件:
这个批处理文件完成了我在答案开头所描述的内容。请确保根据需要调整变量SRC_PATH
和ASPECTJ_HOME
。
@echo off
set SRC_PATH=C:\Users\Alexander\Documents\java-src\SO_AJ_ITDStaticMethods
set ASPECTJ_HOME=C:\Program Files\Java\AspectJ
echo Building annotation processor
cd "%SRC_PATH%"
rmdir /s /q bin
del /q processor.jar
set CLASSPATH=%ASPECTJ_HOME%\lib\aspectjrt.jar
call "%ASPECTJ_HOME%\bin\ajc.bat" -1.8 -sourceroots src_apt -d bin
jar -cvf processor.jar -C src_apt META-INF -C bin .
echo.
echo Generating aspects and building project
rmdir /s /q bin .apt_generated
set CLASSPATH=%ASPECTJ_HOME%\lib\aspectjrt.jar;processor.jar
call "%ASPECTJ_HOME%\bin\ajc.bat" -1.8 -sourceroots src -d bin -s .apt_generated -inpath processor.jar -processor de.scrum_master.app.EntityProcessor -showWeaveInfo
echo.
echo Running de.scrum_master.app.Application
java -cp bin;"%ASPECTJ_HOME%\lib\aspectjrt.jar" de.scrum_master.app.Application
运行批处理文件时的控制台日志:
C:\Users\Alexander\Documents\java-src\SO_AJ_ITDStaticMethods>compile_run.bat
Building annotation processor
Manifest wurde hinzugefügt
Eintrag META-INF/ wird ignoriert
META-INF/services/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
META-INF/services/javax.annotation.processing.Processor wird hinzugefügt(ein = 36) (aus = 38)(-5 % verkleinert)
de/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
de/scrum_master/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
de/scrum_master/app/ wird hinzugefügt(ein = 0) (aus = 0)(0 % gespeichert)
de/scrum_master/app/Entity.class wird hinzugefügt(ein = 293) (aus = 200)(31 % verkleinert)
de/scrum_master/app/EntityProcessor.class wird hinzugefügt(ein = 5679) (aus = 2476)(56 % verkleinert)
Generating aspects and building project
Generated aspect de.scrum_master.app.ORMAspect_Group
Generated aspect de.scrum_master.app.ORMAspect_User
Running de.scrum_master.app.Application
call(List de.scrum_master.app.User.filter())
Called filter method!
call(List de.scrum_master.app.Group.filter())
Called filter method!
Etvoilà!最后4行显示了您想要看到的内容:在带注释的目标类中显式声明的静态方法。享受!