คำอธิบายประกอบประเภทเดียวกันหลายรายการในองค์ประกอบเดียว?


92

ฉันพยายามตบคำอธิบายประกอบประเภทเดียวกันสองรายการขึ้นไปในองค์ประกอบเดียวในกรณีนี้คือวิธีการ นี่คือรหัสโดยประมาณที่ฉันกำลังดำเนินการ:

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

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

เมื่อรวบรวมข้อมูลข้างต้น javac บ่นเกี่ยวกับคำอธิบายประกอบที่ซ้ำกัน:

max @ upsight: ~ / work / daybreak $ javac Dupe.java 
Dupe.java:5: คำอธิบายประกอบที่ซ้ำกัน

เป็นไปไม่ได้ที่จะทำซ้ำคำอธิบายประกอบเช่นนี้? พูดอย่างอวดดีสองอินสแตนซ์ของ @Foo ข้างต้นไม่แตกต่างกันเนื่องจากเนื้อหาต่างกันใช่หรือไม่?

หากไม่สามารถทำได้ข้างต้นมีวิธีแก้ไขปัญหาอะไรบ้าง

UPDATE: ฉันถูกขอให้อธิบายกรณีการใช้งานของฉัน นี่ไป

ฉันกำลังสร้างกลไกเชิงไวยากรณ์เพื่อ "แมป" POJO ไปยังที่เก็บเอกสารเช่น MongoDB ฉันต้องการอนุญาตให้ระบุดัชนีเป็นคำอธิบายประกอบบน getters หรือ setters นี่คือตัวอย่างที่สร้างขึ้น:

public class Employee {
    private List<Project> projects;

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

เห็นได้ชัดว่าฉันต้องการค้นหาอินสแตนซ์ของพนักงานได้อย่างรวดเร็วจากคุณสมบัติต่างๆของ Project ฉันสามารถระบุ @Index สองครั้งด้วยค่า expr () ที่แตกต่างกันหรือใช้วิธีการที่ระบุในคำตอบที่ยอมรับ แม้ว่าไฮเบอร์เนตจะทำเช่นนี้และไม่ถือว่าเป็นการแฮ็ก แต่ฉันคิดว่าอย่างน้อยก็ยังเหมาะสมที่จะอนุญาตให้มีคำอธิบายประกอบประเภทเดียวกันหลายรายการในองค์ประกอบเดียว


1
มีความพยายามที่จะให้กฎที่ซ้ำกันนี้ผ่อนคลายเพื่ออนุญาตให้โปรแกรมของคุณใน Java 7 โปรดอธิบายกรณีการใช้งานของคุณได้หรือไม่?
notnoop

ฉันได้แก้ไขคำถามพร้อมคำอธิบายว่าทำไมฉันถึงต้องการทำสิ่งนี้ ขอบคุณ.
สูงสุดอ.

อาจเป็นประโยชน์ใน CDI เพื่อให้สามารถจัดเตรียม bean สำหรับคุณสมบัติหลายตัวได้ ตัวอย่างเช่นฉันเพิ่งพยายามนำถั่วกลับมาใช้ใหม่ในสองที่โดยระบุว่า "@Produces @PackageName (" test1 ") @PackageName (" test2 ")"
Richard Corfield

เพิ่มเติม: คำตอบด้านล่างไม่สามารถแก้ปัญหานั้นได้เนื่องจาก CDI จะมองว่าคอมโพสิตเป็นหนึ่งรอบคัดเลือก
Richard Corfield

@ แม็กซ์ โปรดเปลี่ยนการยอมรับ "กาเขียว" ของคุณเป็นคำตอบที่ถูกต้องโดย mernst Java 8 เพิ่มความสามารถในการทำคำอธิบายประกอบซ้ำ
Basil Bourque

คำตอบ:


143

ไม่อนุญาตให้ใช้คำอธิบายประกอบประเภทเดียวกันสองรายการขึ้นไป อย่างไรก็ตามคุณสามารถทำสิ่งนี้ได้:

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

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

คุณจะต้องจัดการคำอธิบายประกอบ Foos ในโค้ดโดยเฉพาะ

btw ฉันเพิ่งใช้เมื่อ 2 ชั่วโมงที่แล้วเพื่อแก้ไขปัญหาเดียวกัน :)


2
คุณสามารถทำสิ่งนี้ใน Groovy ได้หรือไม่?
Excel20

5
@ Excel20 ใช่ @Foos([@Foo(bar="one"), @Foo(bar="two")])คุณจะต้องใช้วงเล็บแม้ว่าเช่น ดูgroovy.codehaus.org/Annotations+with+Groovy
sfussenegger

สายไปหน่อยในวันนี้ แต่สนใจที่จะชี้ไปที่คำแนะนำที่สามารถประมวลผลรายการ Foo ภายใน Foos ในขณะนี้ฉันพยายามที่จะสรุปผลลัพธ์ของวิธีการ แต่แม้ว่า Foos จะถูกสกัดกั้น แต่ก็ไม่เคยป้อนคำแนะนำ Foo
Stelios Koussouris

อัปเดต:ตั้งแต่ Java 8 คำตอบนี้ล้าสมัย ดูคำตอบสมัยใหม่ที่ถูกต้องโดย mernst Java 8 เพิ่มความสามารถในการทำซ้ำคำอธิบายประกอบ
Basil Bourque

66

การใส่คำอธิบายประกอบซ้ำใน Java 8

ในJava 8 (เผยแพร่ในเดือนมีนาคม 2014) สามารถเขียนคำอธิบายประกอบซ้ำ / ซ้ำกันได้

ดูบทแนะนำการทำซ้ำคำอธิบายประกอบการทำซ้ำคำอธิบายประกอบ

ดูสเปคJEP 120: คำอธิบายประกอบการทำซ้ำ


1
เอกสารอย่างเป็นทางการdocs.oracle.com/javase/tutorial/java/annotations/repeating.html
Anderson

21

นอกเหนือจากวิธีอื่น ๆ ที่กล่าวมาแล้วยังมีวิธี verbose ที่น้อยกว่าอีกวิธีหนึ่งใน Java8:

@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{

}

ตัวอย่างโดยค่าเริ่มต้นรับFooContainerเป็นคำอธิบายประกอบ

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

ทั้งสองพิมพ์ด้านบน:

@ com.FooContainer (value = [@ com.Foo (value = 1), @ com.Foo (value = 2), @ com.Foo (value = 3)])

@ com.FooContainer (value = [@ com.Foo (value = 1), @ com.Foo (value = 2), @ com.Foo (value = 3)])


ควรระบุว่าชื่อเมธอด / ฟิลด์ใน FooContainer ต้องมีชื่อว่า "value ()" ไม่งั้นฟูจะคอมไพล์ไม่ได้
Tomasz Mularczyk

... นอกจากนี้ยังมีประเภทคำอธิบายประกอบ (FooContainer) ไม่สามารถใช้ได้กับประเภทมากกว่าประเภทคำอธิบายประกอบที่ทำซ้ำได้ (Foo)
Tomasz Mularczyk

16

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

เริ่มจาก Java8 คุณสามารถอธิบายคำอธิบายประกอบที่ทำซ้ำได้:

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

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

บันทึก, valueเป็นฟิลด์ที่จำเป็นสำหรับรายการค่า

ตอนนี้คุณสามารถใช้คำอธิบายประกอบที่ทำซ้ำแทนการเติมอาร์เรย์:

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

12

ดังที่กล่าวโดย sfussenegger สิ่งนี้เป็นไปไม่ได้

วิธีแก้ปัญหาปกติคือการสร้างคำอธิบายประกอบ "หลายรายการ"ซึ่งจัดการอาร์เรย์ของคำอธิบายประกอบก่อนหน้านี้ โดยทั่วไปจะมีชื่อเหมือนกันโดยมีคำต่อท้าย "s"

อย่างไรก็ตามสิ่งนี้ถูกใช้อย่างมากในโครงการสาธารณะขนาดใหญ่ (เช่นไฮเบอร์เนต) ดังนั้นจึงไม่ควรถือเป็นการแฮ็ก แต่เป็นวิธีแก้ปัญหาที่ถูกต้องสำหรับความต้องการนี้


ขึ้นอยู่กับความต้องการของคุณอาจจะดีกว่า อนุญาตให้คำอธิบายประกอบก่อนหน้าของคุณจัดการกับค่าต่างๆได้ต่างๆได้

ตัวอย่าง:

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

ฉันรู้ว่าสิ่งนี้คุ้นเคยอย่างน่าประหลาด ขอบคุณที่ทำให้ความทรงจำของฉันสดชื่น
สูงสุดอ.

ตอนนี้สามารถทำได้ด้วย Java 8
Anis LOUNIS

4

การรวมคำตอบอื่น ๆ ไว้ในรูปแบบที่ง่ายที่สุด ... คำอธิบายประกอบพร้อมรายการค่าอย่างง่าย ...

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

//...

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

3

หากคุณมีเพียง 1 พารามิเตอร์ "bar" คุณสามารถตั้งชื่อเป็น "value" ได้ ในกรณีนี้คุณจะไม่ต้องเขียนชื่อพารามิเตอร์เลยเมื่อคุณใช้เช่นนี้:

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

สั้นกว่าและเรียบร้อยกว่านิดนึงอิมโฮ ..


ประเด็นที่ถูกต้อง แต่วิธีนี้จะพยายามตอบคำถามของ OP อย่างไร?
หมอเดชชัย

@MouseEvent คุณพูดถูกฉันคิดว่ามันเป็นการปรับปรุงคำตอบยอดนิยมจาก sfussenegger มากกว่าและเป็นส่วนหนึ่งในความคิดเห็นที่นั่น แต่คำตอบก็ล้าสมัยอยู่ดีเนื่องจากคำอธิบายประกอบที่ทำซ้ำได้ ...
golwig

0

ใน Java เวอร์ชันปัจจุบันฉันสามารถแก้ไขปัญหานี้ได้ด้วยคำอธิบายประกอบต่อไปนี้:

@Foo({"one", "two"})

1
รุ่นไหน? jdk 8,9,10,11?
Gaurav
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.