自動メソッドを置き換える生成します

Sumsar1812:

私が作っていたアプリケーションのための言語ファイルを作成するときに、私は定型コードの多くに実行しています。私は現在、その中のすべての言語の文字列を持つクラスを持っているし、私は、ファイルにこれらの文字列を書き込むためにリフレクションを使用しています。

私はかなり頻繁に実行すると、例えば、私は、このような文字列を持っているかもしれませんが、私は交換したいというのが私の文字列内の特定のプレースホルダを持っているということです。

public static String USER_INFO = "Username: %name% money: %balance%";

私は何を達成したいことは、私はゲッター/セッターやロンボクと他の方法を生成することができますように注釈に基づいていくつかのメソッドを生成することです。上記の文字列に基づいて、私はと呼ばれるアノテーションを持っていますArguments:ここで見るように(適切に代替品以上の意味のある何か命名されているはずですが)

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.FIELD)
public @interface Arguments {
  String[] value();
}

私は何をしたいのは、このように注釈を追加することです。

@Arguments(
        value = {"%balance%", "%name%"}
)
public static String USER_INFO = "Username: %name% - money: %balance%";

そして、次の代替方法の自動生成されます:

public static String USER_INFONameReplacement(String name) {
    return USER_INFO.replace("%name%", name);
}
public static String USER_INFOAllReplacement(String name, String balance) {
    return USER_INFO.replace("%name%", name).replace("%balance%", balance);
}
public static String USER_INFOBalanceReplacement(String balance) {
    return USER_INFO.replace("%balance%", balance);
}

いくつかの検索を行った後、私はこのようなクラスでAbstractProcessorを実装しようとしてしまいました。

@SupportedAnnotationTypes(
    {"io.github.freakyville.configHelper.annotations.Arguments"})
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@AutoService(Processor.class)
public class SuggestProcessor extends AbstractProcessor {

@Override
public synchronized void init(ProcessingEnvironment env) {
}

@Override
public boolean process(Set<? extends TypeElement> annoations, RoundEnvironment env) {
    for (TypeElement annoation : annoations) {
        Set<? extends Element> annotatedElements = env.getElementsAnnotatedWith(annoation);
        Map<Boolean, List<Element>> annotatedFields = annotatedElements.stream().collect(
                Collectors.partitioningBy(element ->
                        ((ArrayType) element.asType()).getComponentType().getClass().equals(PrimitiveType.class)));
        List<Element> setters = annotatedFields.get(true);
        if (setters.isEmpty()) {
            continue;
        }
        String className = ((TypeElement) setters.get(0)
                .getEnclosingElement()).getQualifiedName().toString();

        Map<String, List<String>> setterMap = setters.stream().collect(Collectors.toMap(
                setter -> setter.getSimpleName().toString(),
                setter -> Arrays.asList(setter.getAnnotation(Arguments.class).value()))
        );
        try {
            writeBuilderFile(className, setterMap);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return true;
}

private void writeBuilderFile(
        String className, Map<String, List<String>> setterMap)
        throws IOException {

    String packageName = null;
    int lastDot = className.lastIndexOf('.');
    if (lastDot > 0) {
        packageName = className.substring(0, lastDot);
    }

    String builderSimpleClassName = className
            .substring(lastDot + 1);

    JavaFileObject builderFile = processingEnv.getFiler()
            .createSourceFile(className);

    try (PrintWriter out = new PrintWriter(builderFile.openWriter())) {

        if (packageName != null) {
            out.print("package ");
            out.print(packageName);
            out.println(";");
            out.println();
        }

        out.print("public class ");
        out.print(builderSimpleClassName);
        out.println(" {");
        out.println();

        setterMap.forEach((key, orgArgNames) -> {

            for (int i = 0; i < orgArgNames.size(); i++) {
                List<String> subList = orgArgNames.subList(0, i + 1);
                List<String> argNames = subList.stream().map(v -> v.replace("%", "") + "Replacement").collect(Collectors.toList());
                List<String> argsWithTypes = argNames.stream().map(v -> "String " + v).collect(Collectors.toList());
                String argumentList = "(" + String.join("", argsWithTypes).substring(0, argsWithTypes.size() - 3) + ")";
                String methodName;

                if (orgArgNames.size() <= 1) {
                    methodName = key + "Replace" + subList.stream().map(v -> v.replace("%", "")).collect(Collectors.joining(""));
                } else {
                    methodName = key + "Replace" + subList.stream().map(v -> v.replace("%", "").substring(0, 1).toUpperCase() + v.substring(1)).collect(Collectors.joining(""));
                }

                out.print("    public static ");
                out.print(methodName);
                out.print(argumentList);
                out.println("{");
                StringBuilder replaceSB = new StringBuilder();
                replaceSB.append(key);
                for (int i1 = 0; i1 < subList.size(); i1++) {
                    replaceSB
                            .append(".replace(")
                            .append("\"")
                            .append(subList.get(i))
                            .append("\"")
                            .append(",")
                            .append(argNames.get(i))
                            .append(")");

                }
                String replace = replaceSB.toString();
                out.println("return " + replace + ";");
                out.println("}");
                out.println("");
            }
        });

        out.println("}");
    }
}


}

しかし、私は、それはそれを登録するように見えることはできませんか?

私の最初の質問があるので、AbstractProcessorは、私はこれを達成する必要がある場合は移動するための方法ですか?ない場合はどのようにして?yesの場合、なぜこれが登録されていませんか?私IntelliJのを使用していますが、設定に入った - >ビルド - >コンパイラと私のSuggestProcessorに有効になっており、プロセッサのパスを設定する注釈プロセッサを変更

ヤン・ウィレムGmelig郵送:

アノテーション処理(APT)プラグインは、他のクラスに基づいてコードを生成することを意図しています。これらのクラスは、後でうまくとしてコンパイルされて生成されたソースフォルダに終わります。これらのAPTのプラグインは、同様のIntelliJコンパイラによってクラスパス/ビルド・ツールの設定とRANから発見されています。既存のクラスを置き換えるために、すべてのAPTは、生成されたソースコード生成のためであることをメンターではなく、:覚えておいてください。彼らは、コンパイラに非常に深い彼らの方法をハックし、それによって、コンパイルの下のクラスのASTを操作することができますので、ロンボクはまだそうすることが可能である唯一の理由です。

このアプローチは、Javaの将来のバージョンで大幅に物議でエラーが発生しやすいので、誰もが今までにも(ありませんでしたAPTベースクラスの代替フレームワークやこれを実行することができロンボクの延長の構築を試みる可能性はほとんどありませんロンボクは、APTの使用やロンボク自体のこのタイプの「フレームワーク」と考えることができる唯一のツールであるという事実のために、それは)拡張可能な方法で、すべてのビルドではありません。

結論:APTは、おそらく行く方法ですが、あなたのプロセッサは、既存のものを変更しようとするのではなく、新しいクラスを作成する必要があります。

あなたは以下のリポジトリを見ることができます注釈プロセッサを作成する方法の例:https://github.com/galberola/java-apt-simple-example

私はあなたの現在の注釈プロセッサは、コンパイラに正しく関連付けられていない理由はわかりません。あなたはMavenを使用している場合は、ローカルであなたのプロセッサのためのアーティファクトをインストールして、他のプロジェクトへのコンパイル依存関係としてそれを追加しようとすることができ。あまりにもあなたのコンパイラで注釈プロセッサとしてクラスを登録することを忘れないでください、私は参照することをサンプルプロジェクトは、ここでは、この処理を行います。https://github.com/galberola/java-apt-simple-example/blob/master/example/ pom.xml#L29-L31同じ構成には、あまりにも他のビルドシステムに適用することができます。

あなたが本当に残念ながら、この同じクラスにメソッドを持っている必要がありそうだとすれば、コンパイルの下のクラスを変更するJavaで何の現実的な方法は、それを行うことができないという意味では、ありません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=229662&siteId=1