2016-09-25 14 views
1

目的:私の@Entityクラスのいずれかからクラスのstatic filter()メソッドを呼び出します。 List<Objectを返します。適切なクラスの呼び出し元の種類を取得します。 たとえば、Userクラスからfilter()を呼び出すと、元の静的メソッドを所有するクラスではなく、呼び出し元クラスとしてUserを取得します。AspectJ - 継承された 'parents'クラスのポイントカット

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(); 

ユーザーである私は、この点を書いた

public static List<Object> filter(){ 
    System.out.println("Called filter method!"); 
    return Collections.emptyList(); 
} 

このfilter()方法はORMEntityであります単純な豆で@Entity注釈。

これは、そのように働いている:

  1. コンパイラがUserクラスからfilter()方法を参照してください。 OK。
  2. filter()のポイントカットは、User extends ORMEntity(次にfilter()メソッド)でもORMEntity.filter()にあるだけです。よくない。

    System.out.println(">>"+thisJoinPoint.getSignature().getDeclaringType()); 
    

    は私が予想ORMEntity代わりのUserです:

filter()前からの出力はポイントに参加します。

Userクラスを取得するには、static filter()メソッドを継承しますか? AspectJのdeclare parentにポイントカットのようなものがありますか?

+0

宣言型は '​​filter()'メソッドを宣言しているので、 'ORMEntity'です。非静的メソッドを使用する場合でも、メソッド自体は 'ORMEntity'で '宣言'されますが、インスタンスメソッドも使用していないので、静的メソッドの場合は継承の観点から考えるべきではありませんメソッド。私はここで何を達成しようとしているのかよくわからないので、もう少し詳しいことを述べたいと思うと便利かもしれません。 –

+0

はい私はそれが独自のfilter()メソッドのORMEntityだと理解しています。私はaspectjを使ってどこからでもこのメソッドを継承できると思っていました。それは動作していますが、Userクラスで呼び出しても呼び出し元はORMEntityのままです。実際には、このフィルタメソッドを自分の@Entityクラスから静的に呼び出す必要があります。単に「素敵な」「簡単な」コードを持っているだけです。 ORMEntity.filter(User.class)を呼び出す代わりに。私はUser.filter()を呼び出します。誰がORMEntity.filter(User.class)を呼び出していますか。バックグラウンドでだから私は正しいクラスの呼び出し元を取得するために検索しています。 – Tokazio

+0

静的メソッド呼び出しの精巧さ:コンパイラは 'staticMethod()'自体がスーパークラスで宣言されていても 'Subclass.staticMethod()'と言うことができますが、コンパイラが寛大であるあなたの意図。実際には、バックグラウンドでメソッド呼び出しを 'DeclaringClass.staticMethod()'に変換しています。一方、私が正しく理解していれば、コードが実際に静的メソッドを呼び出すクラスを知りたいと思っています。 'call(...) 'タイプのポインターカットでは完全に可能です。実際は式は' thisEnclosingJoinPointStaticPart'です。 –

答えて

0

と思われます。

Userクラスのstatic ORMEntity filter()メソッドを非表示にする必要があります。 しかし、静的メソッドはコンパイル時に解決されます。

私が見る唯一の解決策は、lombokがgetters/settersで行うことができるように、.javaファイルにstatic filter()メソッドを生成することです。

+0

問題は不可能ではありませんが、それは意味をなさないことです! JVMの動作方法を変更する必要があります。これはAspectJの問題ではありません!!! **本当にあなたがITDを使って各 '@ Entity'クラスのメソッドを重複して宣言することができると主張すれば、それから、あなたが望むものを手に入れることができますが、それは非効率的で、ちょっとばかばかしいと思います(申し訳ありませんが、違反は意味しません)。なぜ、JVMが(効率的な)方法を変更したいのですか? – kriegaex

+0

を呼び出す代わりに、ORMEntity.filter(User.class)を呼び出します。私はUser.filter()を呼び出します。誰がORMEntity.filter(User.class)を呼び出して、さらにコードを書く必要はありません。 「可能」なミスをしないようにしてください。 ITDとは何ですか? – Tokazio

+0

ITDはinter-type宣言、つまり 'declare parents 'ですでに使用しているような静的なクロスカットです。 AspectJ ITDを使用してクラスのメソッドを宣言することもできますが、あなたの場合の欠点は、クラスを1つだけにしたくないということです。私。 1つの注釈付きクラスごとに静的メソッドを宣言する必要があります。これを実現するには、[v1.8.2リリースノート](http://www.eclipse.org/aspectj/doc/released/README-182.html)に記載されているAspectJのアノテーション処理機能を使用できます。しかし、努力する価値はあるのでしょうか?私は、あなたのアプリケーションのデザインには欠陥があると思います。 – kriegaex

0

あなた自身の答えで説明したように、私はあなたのアプリケーション設計が本当に意味をなさないとは思っていますが、それが価値あるものであれば、AspectJ's annotation processing capability introduced in version 1.8.2を使って解決策を用意しました。この解決法は、私がanother StackOverflow answerのはるかに複雑なケースのために説明したものの単純化されたバージョンです。ここで

は、二つのソースフォルダと二相コンパイルプロセスを実行するWindowsバッチファイルと私のEclipseのレイアウトである

  • は、まず、注釈付きクラス
  • あたり一面の作成を担当APTプロセッサをコンパイルし、次のAspectJコンパイル・ステップで実際にこのプロセッサーをJavaソースに適用します。ここで

私のディレクトリレイアウトのスクリーンショットです:

Eclipse directory layout

あなたが見ることができるように、クラス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_PATHASPECTJ_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行は、見たいものを表示します。注釈付きターゲットクラスで明示的に宣言された静的メソッド。楽しい!

関連する問題