質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.49%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Q&A

解決済

3回答

7772閲覧

Java アノテーションがついたクラスのアノテーションの値の取得方法

katliner

総合スコア13

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

0グッド

1クリップ

投稿2018/02/04 13:28

編集2018/02/04 14:25

例えば@Modというアノテーションがあったとします。
Mod

Java

1import java.lang.annotation.ElementType; 2import java.lang.annotation.Retention; 3import java.lang.annotation.RetentionPolicy; 4import java.lang.annotation.Target; 5 6@Retention(RetentionPolicy.RUNTIME) 7@Target(ElementType.TYPE) 8public @interface Mod { 9 String name() default ""; 10}

nameという値がセットできるようにするとします。
そしてあるクラスに

Java

1@Mod(name="test") 2public class Test{ 3 4}

というふうに書かれています。
これがzipファイルにされており、zipファイルをClassLoaderにしてClass.forNameでクラスを取得しています。
zipファイルの物はライブラリとして@Modを使っていて、そのライブラリは同包していません。
メインのクラスが

Java

1public static void main(String[] args) { 2 ClassLoader loader = new JarFileClassLoader(new File("test.zip"), ClassLoader.getSystemClassLoader()); 3 Class clas = Class.forName("Test",false,loader); 4 for(Annotation anno : clas.getAnnotations()) { 5 if (anno.annotationType().equals(Mod.class)) { 6 Mod b = (Mod) anno; 7 System.out.println("Value: " + b.name()); 8 } 9 } 10}

となっておりJarFileClassLoaderというのがこれです

java

1import java.io.File; 2import java.net.MalformedURLException; 3import java.net.URL; 4import java.net.URLClassLoader; 5 6/** 7 * JARファイルからクラスを読み込むクラスローダー 8 * @author NAT 9 */ 10public class JarFileClassLoader extends URLClassLoader { 11 /** 12 * コンストラクタ 13 * @param jarFiles クラスを読み込むJARファイルの配列 14 * @param parent 親となるクラスローダー 15 * @throws MalformedURLException パスを URL として構文解析できない場合 16 */ 17 public JarFileClassLoader(File[] jarFiles, ClassLoader parent) throws MalformedURLException { 18 super(toURLs(jarFiles), parent); 19 } 20 21 /** 22 * コンストラクタ 23 * @param jarFile クラスを読み込むJARファイル 24 * @param parent 親となるクラスローダー 25 * @throws MalformedURLException パスを URL として構文解析できない場合 26 */ 27 public JarFileClassLoader(File jarFile, ClassLoader parent) throws MalformedURLException { 28 this(new File[]{jarFile}, parent); 29 } 30 31 private static URL[] toURLs(File[] jarFiles) throws MalformedURLException { 32 URL[] urls = new URL[jarFiles.length]; 33 for (int i = 0; i < jarFiles.length; i++) { 34 urls[i] = jarFiles[i].toURL(); 35 } 36 return urls; 37 } 38}

するとメインのクラスの

if (anno.annotationType().equals(Mod.class))

がうまく動作しません。
おそらく別のクラスと認識されているのかと思います。
どうしたらうまく動作しますか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/02/04 13:46

あw 前の質問にそれだろうなとおもって回答を作ってたら
smk7758

2018/02/04 14:08

なるほど。マルチポストは控えてください。
katliner

2018/02/04 14:09

以後気をつけます。
guest

回答3

0

とりま Class の所在が分からないようなので前述の質問ではアノテーションが取得できたので強制取得はこちらでいけるはず

String ano = "@Mod(name=TestMod)"; String name = ano.replaceAll("^.*[ (,]name=(.*?)[,)].*$", "$1"); System.out.println(name);

投稿2018/02/04 14:30

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

自己解決

自己解決しました
どうやらJarFileClassLoaderでは独自のClassLoaderを作ってしまうらしく
importは同じクラスに見えますがClassLoaderが違うと同じクラスとは扱えないということだったみたいです。その記事
ということでClassLoader loader = new JarFileClassLoader(new File("test.zip"), ClassLoader.getSystemClassLoader());とせず、
ClassLoader loader = new URLClassLoader(new URL[] {new File("test.zip").toURL()},this.getClass().getClassLoader());
としてClassLoaderを作れば外部ファイルのClassLoaderでも同じClassLoaderとして扱ってくれるようになり、import先が同じものになりました。
アノテーションの取得は
clas.getAnnotation(Mod.class)
だけで取得できるようになりました。

投稿2018/02/05 14:28

編集2018/02/05 14:29
katliner

総合スコア13

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

java

1for (Annotation annotation : this.getClass().getAnnotations()) { 2 System.out.println("Type: " + annotation.annotationType().getName()); 3 if (annotation.annotationType().equals(Description.class)) { 4 Description description = (Description) annotation; 5 System.out.println("Value: " + description.value()); 6 } 7}

リフレクションですね。(こちら事情ですが、携帯からなので打ちづらい)
thisを任意クラスのオブジェクト, Descriptionを任意の注釈にすることで可能です。
またvalue()のように値を返すメソッドがない場合は別の対応が必要です。(privateフィールドにアクセスかなぁ)

投稿2018/02/04 13:47

編集2018/02/04 13:54
smk7758

総合スコア36

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

katliner

2018/02/04 13:51

DescriptionはModに変えたらいいですか?
katliner

2018/02/04 13:56

試しに必要なところだけ書き換えて見ましたがType:の結果とクラスファイルの場所は同じですがif文の中が実行されません...ちょっと質問に追記します
smk7758

2018/02/04 14:02

そのソースをいただけますか?
katliner

2018/02/04 14:03

質問文に追記します
katliner

2018/02/04 14:13

追記しました
smk7758

2018/02/04 14:25

エラーなしですよね。 うーん…力になれそうにないです。
katliner

2018/02/04 14:32

for(Annotation anno : clas.getAnnotations()) { のあとanno.toString().startWithでクラスを確認してMod m = (Mod)anno;としてもキャストのエラーがでてしまいます。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.49%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問