あなた自身の答えで説明したように、私はあなたのアプリケーション設計が本当に意味をなさないとは思っていますが、それが価値あるものであれば、AspectJ's annotation processing capability introduced in version 1.8.2を使って解決策を用意しました。この解決法は、私がanother StackOverflow answerのはるかに複雑なケースのために説明したものの単純化されたバージョンです。ここで
は、二つのソースフォルダと二相コンパイルプロセスを実行するWindowsバッチファイルと私のEclipseのレイアウトである
- は、まず、注釈付きクラス
- あたり一面の作成を担当APTプロセッサをコンパイルし、次のAspectJコンパイル・ステップで実際にこのプロセッサーをJavaソースに適用します。ここで
私のディレクトリレイアウトのスクリーンショットです:
あなたが見ることができるように、クラスApplication
は直接のEclipseでコンパイルすることができない、あなたが本当にバッチファイルを使用する必要があります。
マーカー注釈:
注意、このクラスは、注釈プロセッサEntityProcessor
後 ために見えるようにするためにsrc_apt内に格納されなければなりません。
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();
}
}
メソッドのシグネチャを印刷アスペクト比:
これは、任意の親や静的メソッドを宣言しない、メソッドのシグネチャを印刷し、あなたの元の縦横のsimpilfiedバージョンです。これはちょうど、後でよりよいログ出力を得るためにある:
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 /サービス/ javax.annotation.processing.Processorの内容です:
de.scrum_master.app.EntityProcessor
バッチファイル2相コンパイルを実行する:
このバッチファイルは、私が答えの冒頭で説明したことを行います。変数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!
のEtの出来上がり!最後の4行は、見たいものを表示します。注釈付きターゲットクラスで明示的に宣言された静的メソッド。楽しい!
宣言型は 'filter()'メソッドを宣言しているので、 'ORMEntity'です。非静的メソッドを使用する場合でも、メソッド自体は 'ORMEntity'で '宣言'されますが、インスタンスメソッドも使用していないので、静的メソッドの場合は継承の観点から考えるべきではありませんメソッド。私はここで何を達成しようとしているのかよくわからないので、もう少し詳しいことを述べたいと思うと便利かもしれません。 –
はい私はそれが独自のfilter()メソッドのORMEntityだと理解しています。私はaspectjを使ってどこからでもこのメソッドを継承できると思っていました。それは動作していますが、Userクラスで呼び出しても呼び出し元はORMEntityのままです。実際には、このフィルタメソッドを自分の@Entityクラスから静的に呼び出す必要があります。単に「素敵な」「簡単な」コードを持っているだけです。 ORMEntity.filter(User.class)を呼び出す代わりに。私はUser.filter()を呼び出します。誰がORMEntity.filter(User.class)を呼び出していますか。バックグラウンドでだから私は正しいクラスの呼び出し元を取得するために検索しています。 – Tokazio
静的メソッド呼び出しの精巧さ:コンパイラは 'staticMethod()'自体がスーパークラスで宣言されていても 'Subclass.staticMethod()'と言うことができますが、コンパイラが寛大であるあなたの意図。実際には、バックグラウンドでメソッド呼び出しを 'DeclaringClass.staticMethod()'に変換しています。一方、私が正しく理解していれば、コードが実際に静的メソッドを呼び出すクラスを知りたいと思っています。 'call(...) 'タイプのポインターカットでは完全に可能です。実際は式は' thisEnclosingJoinPointStaticPart'です。 –