LoginSignup
ponch
@ponch

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Fileクラスで得たjavaファイル中にあるメソッド一覧の取得方法

Fileクラスで得たjavaファイル中にあるメソッド一覧の取得方法

私は今、javaで、ファイルチューザにより、javaファイルを読み込んで、その選択したjavaファイル中にあるメソッドの一覧を取得したいのですが、よくわからないので、方法を教えてください。

0

7Answer

@javaboy
Class.forNameはclassファイル(拡張子が.classのファイル)を読み込む処理ですので、質問者様が言っているjavaファイルを読み込むという要件には合致しないかと思います。
※Class.forNameが動くにはClassLoaderによってclassファイルもしくはjarファイルがjvm上に読み込まれている必要があります。

@ponch
「JavaParserの使い方がわからないから他の手段を検討する」ということ自体に問題はありませんが、質問内容からしてもJavaParserが一番の近道かと思われます。
具体的にどの使い方がわからないのでしょうか。
https://qiita.com/opengl-8080/items/50ddee7d635c7baee0ab
こちらの記事はとても詳しく記載されていますので、質問者様が求めている情報は取得できるかと思いおます。
こちらの記事ではJavaParserを使うためにGradleを使用しているので、Gradleの使い方から調べてみてはどうでしょうか。

もしJavaParserを使わない場合は、以下のような方法が考えられます。
①javaファイルをコンパイルしたのち、「javap」コマンドもしくは「jad」コマンドを使用して、解析する(javaファイルをコンパイルできる場合に限ります。)
②javaの文法に沿った正規表現などを作成し、地道に調べる。これについては車輪の再発明ですのであまりおすすめできません。

1Like
File file = ...
Path directory = Path.of(file.toURI());
try {
    for (Path path:pathFiles.newDirectoryStream(directory) {
        File file2 = path.toFile();// file2はfileの中に入っているファイル
    }
}catch (IOException e) {
    e.printStackTrace();
}

参考

0Like

Comments

  1. @ponch

    Questioner
    for分の()の中のpathFilesに関してエラーが出るのですが、これは、何ですか?

すみません。入力ミスです。修正しました↓また、ファイルチューザとは違うかもしれませんが

File file = ...
Path directory = Path.of(file.toURI());
try {
    for (Path path:Files.newDirectoryStream(directory) {
        File file2 = path.toFile();// file2はfileの中に入っているファイル
    }
}catch (IOException e) {
    e.printStackTrace();
}

0Like

Comments

  1. @ponch

    Questioner
    コンパイルはできましたが、実行でエラーが出ました。
    File file2 = path.toFile();// file2はfileの中に入っているファイル
    ここで、javaファイルの中に入っているメソッドが得られるのですか?

すみません。タイトルをしっかり読んでなくてフォルダの中のファイル一覧を取得したいのかと誤って認識してしまいました。そんな時はリフレクションを使ってはいかがでしょうか。

public class Main{
    public static void main(String[] args) {}
        et<String> methodNameList = new HashSet<>;//メソッドの名前一覧
        try {
                Class<?> stringClass = Class<?>.forName(args[0]);//コマンドライン引数にしていされたクラスを取得
                Method[] methods = stringClass.getMethods();// メソッド一覧を取得
                for (Method method : methods) {
                    methodNameList.add(method.getName());// methodNameListにメソッド名を追加
                }
        } catch (ClassNotFoundException e) {
             // java.lang.Stringが存在しなかった場合
        }  catch (SecurityException e) {
            // メソッド一覧を取得できなかった場合
        }
        methodNameList.stream().forEach(System.out::println); // メソッド一覧を表示
    }
}

これがリフレクションです。しかし、リフレクションは処理を遅くするため注意してください。

0Like

Comments

  1. @ponch

    Questioner
    すみません。これに関しては理解できるのですが、
    これを、実行中に選んだjavaファイル(クラス)に対して行いたいのです。
    できたりしますか?

Comments

  1. @ponch

    Questioner
    JavaParserは使いたいなと思っていたのですが、github上にあるものの使い方がわからず諦めていました。このサイトも見たことありますが、よくわかりませんでした。

これではだめでしょうか。クラスパスが入っている前提の話になりますが、

コマンドライン引数を使う方法
public class Main {
    public static void main(String[] args) throws ClassNotFoundException{
        Class<?> classInstance = Class<?>.forName(args[0]);
        // リフレクション処理
    }
}
実行方法
java Main java.lang.String
ファイルからpackage文を検索する方法
Path file = ...
String packageName = Files.lines(file).fillter(s -> s.matches("^package .*")).collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).substring(8);
packageName = packageName.substring(0, packageName.length() - 1);
Class<?> classInstance = Class<?>.forName(packageName + "." + file.getFileName());
// リフレクション処理

未検証ですので、エラーなどあれば、教えてください

0Like

Comments

  1. @ponch

    Questioner
    Class<?> classInstance = Class<?>.forName(packageName + "." + file.getFileName());
    ここの文でエラーが出てきます。色々試しましたが、実行でうまくいきませんでした。

修正しました。

Main.java
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.Files;

public class Main {
    public static void main(String[] args) throws Exception{
        Path file = Paths.get("Main.java");
        String packageName = "";
        try {
            packageName = Files.lines(file).filter(s -> s.matches("^package .*")).collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).substring(8);
            packageName = packageName.substring(0, packageName.length() - 1);
        } catch (StringIndexOutOfBoundsException e) {}
        Class<?> classInstance = Class.forName(packageName + (packageName == "" ? "" : ".") + file.getFileName().toString().substring(0, file.getFileName().toString().length() - 5));
        // リフレクション処理
    }
}
0Like

Your answer might help someone💌