Bir öğe üzerinde aynı türden birden çok açıklama var mı?


91

Aynı türden iki veya daha fazla ek açıklamayı tek bir öğeye, bu durumda bir yönteme tokatlamaya çalışıyorum. İşte üzerinde çalıştığım yaklaşık kod:

public class Dupe {
    public @interface Foo {
      String bar();
    }

    @Foo(bar="one")
    @Foo(bar="two")
    public void haha() {}
}

Yukarıdakileri derlerken javac, yinelenen bir ek açıklamadan şikayet eder:

max @ upight: ~ / work / daybreak $ javac Dupe.java 
Dupe.java:5: yinelenen ek açıklama

Bunun gibi ek açıklamaları tekrarlamak mümkün değil mi? Ufak tefek konuşmak gerekirse, içeriklerinin farklı olması nedeniyle yukarıdaki iki @Foo örneği farklı değil mi?

Yukarıdakiler mümkün değilse, bazı olası geçici çözümler nelerdir?

GÜNCELLEME: Kullanım durumumu açıklamam istendi. İşte başlıyor.

MongoDB gibi mağazaları belgelemek için POJO'ları "eşlemek" için şeker gibi bir sözdizimi mekanizması oluşturuyorum. Alıcılarda veya ayarlayıcılarda ek açıklamalar olarak dizinlerin belirtilmesine izin vermek istiyorum. İşte uydurma bir örnek:

public class Employee {
    private List<Project> projects;

    @Index(expr = "project.client_id")
    @Index(expr = "project.start_date")
    public List<Project> getProjects() { return projects; }
}

Açıkçası, Projenin çeşitli özelliklerine göre Çalışan örneklerini hızlı bir şekilde bulabilmek istiyorum. Ya @Index'i farklı ifade () değerleriyle iki kez belirtebilirim veya kabul edilen yanıtta belirtilen yaklaşımı kullanabilirim. Hibernate bunu yapıyor ve bir hack olarak görülmese de, en azından tek bir öğede aynı türden birden fazla ek açıklamaya izin vermenin yine de mantıklı olduğunu düşünüyorum.


1
Java 7'de programınıza izin vermek için bu yinelenen kuralın gevşetilmesi için bir çaba var. Kullanım durumunuzu açıklar mısınız lütfen?
notnoop

Sorumu neden bunu yapmak istediğimin bir açıklamasıyla düzenledim. Teşekkürler.
Max A.

Bir çekirdeğin birden çok niteleyici için sağlanmasına izin vermek CDI'da kullanışlı olabilir. Örneğin, bir fasulyeyi "@Produces @PackageName (" test1 ") @PackageName (" test2 ")" olarak nitelendirerek iki yerde yeniden kullanmayı denedim
Richard Corfield

Ayrıca: Aşağıdaki yanıt bu sorunu çözmez çünkü CDI bileşiği bir Niteleyici olarak görür.
Richard Corfield

@MaxA. Lütfen "yeşil onay" kabulünüzü mernst tarafından doğru Cevapla değiştirin. Java 8, açıklamaları tekrarlama yeteneği ekledi.
Basil Bourque

Yanıtlar:


140

Aynı türden iki veya daha fazla ek açıklamaya izin verilmez. Ancak bunun gibi bir şey yapabilirsiniz:

public @interface Foos {
    Foo[] value();
}

@Foos({@Foo(bar="one"), @Foo(bar="two")})
public void haha() {}

Yine de, kodda Foos ek açıklamasının özel olarak işlenmesine ihtiyacınız olacak.

btw, bunu 2 saat önce aynı sorunu çözmek için kullandım :)


2
Bunu Groovy'de de yapabilir misin?
Excel20

5
@ Excel20 Evet. Yine de köşeli parantez kullanmanız gerekir, örneğin @Foos([@Foo(bar="one"), @Foo(bar="two")]). See groovy.codehaus.org/Annotations+with+Groovy
sfussenegger

Günün biraz gecikmesine rağmen, Foos'un içindeki Foo listesini işleyebilecek tavsiyelere dikkat edin. Şu anda bir yöntemin sonucunu işlemeye çalışıyorum, ancak Foos'un ele geçirilmesine rağmen Foo tavsiyesi asla
girilmiyor

Güncelleme: Java 8 itibariyle, bu Cevap güncel değildir. Bkz doğru Modern Cevap mernst tarafından. Java 8, açıklamaları tekrarlama yeteneği ekledi.
Basil Bourque


21

Belirtilen diğer yolların yanı sıra, Java8'de daha az ayrıntılı bir yol var:

@Target(ElementType.TYPE)
@Repeatable(FooContainer.class)
@Retention(RetentionPolicy.RUNTIME)
@interface Foo {
    String value();

}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface FooContainer {
        Foo[] value();
        }

@Foo("1") @Foo("2") @Foo("3")
class Example{

}

Varsayılan FooContainerolarak örnek, Ek Açıklama olarak alır

    Arrays.stream(Example.class.getDeclaredAnnotations()).forEach(System.out::println);
    System.out.println(Example.class.getAnnotation(FooContainer.class));

Her ikisi de yukarıdaki baskı:

@ com.FooContainer (değer = [@ com.Foo (değer = 1), @ com.Foo (değer = 2), @ com.Foo (değer = 3)])

@ com.FooContainer (değer = [@ com.Foo (değer = 1), @ com.Foo (değer = 2), @ com.Foo (değer = 3)])


FooContainer'daki yöntem / alan adının kesinlikle "değer ()" olarak adlandırılması gerektiğine işaret etmeye değer. Aksi takdirde Foo derlenmeyecektir.
Tomasz Mularczyk

... ayrıca açıklama türü (FooContainer) içeren, tekrarlanabilir açıklama türünden (Foo) daha fazla türe uygulanamaz.
Tomasz Mularczyk

16

http://docs.oracle.com/javase/tutorial/java/annotations/repeating.html

Java8'den başlayarak tekrarlanabilir notları tanımlayabilirsiniz:

@Repeatable(FooValues.class)
public @interface Foo {
    String bar();
}

public @interface FooValues {
    Foo[] value();
}

Değer valuelistesi için gerekli alandır.

Artık diziyi doldurmak yerine bunları tekrarlayan ek açıklamaları kullanabilirsiniz:

@Foo(bar="one")
@Foo(bar="two")
public void haha() {}

12

Sfussenegger'in söylediği gibi, bu mümkün değil.

Genel çözüm, önceki ek açıklamanın bir dizisini işleyen bir "çoklu" açıklama oluşturmaktır . Tipik olarak bir 's' sonekiyle aynı şekilde adlandırılır.

Bu arada, bu büyük kamu projelerinde çok kullanılıyor (örneğin Hazırda Bekletme), bu yüzden bir hack olarak düşünülmemeli, daha ziyade bu ihtiyaç için doğru bir çözüm.


İhtiyaçlarınıza bağlı olarak, önceki ek açıklamanızın birden çok değeri işlemesine izin vermek daha iyi olabilir .

Misal:

    public @interface Foo {
      String[] bars();
    }

Bunun ürkütücü bir şekilde tanıdık olduğunu biliyordum. Hafızamı tazelediğin için teşekkürler.
Max A.

Artık Java 8 ile mümkün.
Anis

4

diğer cevapları en basit biçimde birleştirmek ... basit bir değerler listesiyle bir açıklama ...

@Foos({"one","two"})
private String awk;

//...

public @interface Foos{
    String[] value();
}

3

Yalnızca 1 parametreniz "bar" varsa, bunu "değer" olarak adlandırabilirsiniz. Bu durumda, bu şekilde kullandığınızda parametre adını yazmanız gerekmez:

@Foos({@Foo("one"), @Foo("two")})
public void haha() {}

biraz daha kısa ve daha düzgün, imho ..


Doğru nokta, ama bu OP'nin sorusuna nasıl cevap vermeye çalışıyor?
Mordechai

@MouseEvent haklısınız, sfussenegger'in en iyi cevabında daha çok bir gelişme olduğunu ve bu nedenle oradaki yorumlara daha çok ait olduğunu düşünüyorum. Ancak cevap tekrarlanabilir açıklamalar nedeniyle zaten geçerliliğini yitirmiş durumda ...
golwig

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.