Pertama: Saya sangat MENCINTAI Project Lombok. Alat yang luar biasa! Ada begitu banyak aspek luar biasa dari perpustakaan 'waktu kompilasi' ini.

Mencintai @ExtensionMethod, saya telah menekan 'fitur' ini beberapa kali, jadi sekarang saatnya bagi saya untuk mengajukan pertanyaan ini:

Misalkan saya memiliki kelas berikut:

@UtilityClass
public class AObject {
    static public String message(final Object pObject) {
        return "AObject = " + (pObject != null);
    }
}
@UtilityClass
public class AString {
    static public String message(final String pObject) {
        return "AString = " + (pObject != null);
    }
}
@ExtensionMethod({ AObject.class, AString.class })
public class Run_Object_String {
    public static void main(final String[] args) {
        System.out.println("\nRun_Object_String.main()");
        final String s = "Bier!";
        final Object o = new Object();

        System.out.println("Testing s: " + s.message());
        System.out.println("Testing o: " + o.message());
        System.out.println("Testing s: " + s.message());
    }
}
@ExtensionMethod({ AString.class, AObject.class })
public class Run_String_Object {
    public static void main(final String[] args) {
        System.out.println("\nRun_String_Object.main()");
        final String s = "Bier!";
        final Object o = new Object();

        System.out.println("Testing s: " + s.message());
        System.out.println("Testing o: " + o.message());
        System.out.println("Testing s: " + s.message());
    }
}
public class ClassPrevalenceTest {
    public static void main(final String[] args) {
        Run_Object_String.main(args);
        Run_String_Object.main(args);
    }
}

Dengan keluaran:

Run_Object_String.main()
Testing s: AObject = true
Testing o: AObject = true
Testing s: AObject = true

Run_String_Object.main()
Testing s: AString = true
Testing o: AObject = true
Testing s: AString = true
  • Kenapa ini?
  • Mengapa message(String) tidak dipanggil pada contoh pertama, meskipun memiliki metode tanda tangan yang lebih cocok daripada message(Object)?
  • Mengapa @ExtensionMethod bergantung pada urutan argumen?

Inilah yang saya asumsikan secara membabi buta:

  • saat parsing untuk ExtensionMethods, Lombok akan memproses nilai anotasi dari kiri ke kanan
    • Untuk Run_Object_String artinya: pertama AObject, lalu AString
    • Untuk Run_String_Object artinya: pertama AString, lalu AObject
  • Object-String: Saat menambal AObject ke dalam kelas Run_Object_String, metode message(Object) akan ditambahkan. Dan saat menambal AString dengan metode message(String), itu tidak akan ditambahkan. Agaknya karena message(Object) juga cocok dengan panggilan ke message(String), jadi message(String) tidak akan ditambahkan.
  • String-Object: Saat menambal AString ke dalam kelas Run_String_Object, metode message(String) akan ditambahkan. Saat menambal di kelas AObject dengan message(Object), metode message(String) yang lama dan sekarang TIDAK akan menerima panggilan message(Object), sehingga metode message(Object) akan ditambahkan.

Jadi, selain sangat memperhatikan urutan apa yang saya tambahkan referensi @UtilityClass, apakah ada solusi lain untuk ini?

  • Bisakah preprocessor Lombok diperpanjang dan dibuat lebih masuk akal saat menambahkan metode ekstensi?
  • Apakah kalian punya saran tentang ini, atau penjelasan tentang apa yang sebenarnya terjadi (berlawanan dengan asumsi saya)
2
JayC667 6 Mei 2021, 18:42

1 menjawab

Jawaban Terbaik

Ini adalah manfaat menarik dari Lombok yang tidak saya sadari. Tempat terbaik yang menurut saya dapat Anda selidiki untuk menemukan jawaban Anda adalah sumbernya sendiri karena dokumen tentang karya eksperimental ini tampaknya cukup ringan, dapat dimengerti.

Lihat git di sini: Tangan .

Saya menduga berdasarkan logika bahwa area yang secara efektif "menyesuaikan" metode yang tepat dari anotasi adalah seperti di bawah ini..

Alih-alih mencoba kecocokan "terbaik", tampaknya bertujuan untuk kecocokan "pertama".

Artinya, tampaknya beralih ke List<Extension> extensions. Karena ini adalah daftar Java, kami menganggap pemesanan dipertahankan dalam urutan ekstensi yang ditentukan dalam anotasi asli.

Tampaknya hanya berfungsi dalam urutan daftar dan return segera setelah ada sesuatu yang cocok dengan metode dan bentuk jenis yang tepat.

Types types = Types.instance(annotationNode.getContext());
        for (Extension extension : extensions) {
            TypeSymbol extensionProvider = extension.extensionProvider;
            if (surroundingTypeSymbol == extensionProvider) continue;
            for (MethodSymbol extensionMethod : extension.extensionMethods) {
                if (!methodName.equals(extensionMethod.name.toString())) continue;
                Type extensionMethodType = extensionMethod.type;
                if (!MethodType.class.isInstance(extensionMethodType) && !ForAll.class.isInstance(extensionMethodType)) continue;
                Type firstArgType = types.erasure(extensionMethodType.asMethodType().argtypes.get(0));
                if (!types.isAssignable(receiverType, firstArgType)) continue;
                methodCall.args = methodCall.args.prepend(receiver);
                methodCall.meth = chainDotsString(annotationNode, extensionProvider.toString() + "." + methodName);
                recursiveSetGeneratedBy(methodCall.meth, methodCallNode);
                return;
            }
        }

Anda dapat melihat sisa kode untuk wawasan lain karena tampaknya tidak terlalu banyak (yaitu jumlah baris) untuk dilihat, meskipun harus diakui ini adalah prestasi yang cukup mengesankan untuk dilakukan di ruang itu.

1
Atmas 11 Mei 2021, 19:19