เป็นไปได้ไหมที่จะอ่านค่าของคำอธิบายประกอบใน java?


102

นี่คือรหัสของฉัน:

@Column(columnName="firstname")


private String firstName;

 @Column(columnName="lastname")
 private String lastName;

 public String getFirstName() {
  return firstName;
 }

 public void setFirstName(String firstName) {
  this.firstName = firstName;
 }

 public String getLastName() {
  return lastName;
 }

 public void setLastName(String lastName) {
  this.lastName = lastName;
 }

เป็นไปได้ไหมที่จะอ่านค่าคำอธิบายประกอบ @Column ของฉัน ( columnName = "xyz123") ในคลาสอื่น

คำตอบ:


123

ใช่ถ้าคำอธิบายประกอบคอลัมน์ของคุณมีการเก็บรักษารันไทม์

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
    ....
}

คุณสามารถทำสิ่งนี้ได้

for (Field f: MyClass.class.getFields()) {
   Column column = f.getAnnotation(Column.class);
   if (column != null)
       System.out.println(column.columnName());
}

อัปเดต: เพื่อรับฟิลด์ส่วนตัวใช้

Myclass.class.getDeclaredFields()

1
ฉันชอบวิธีแก้ปัญหาของคุณ เราจะทำให้มันเป็นแบบทั่วไปได้อย่างไรแทนที่จะเป็น MyClass ฉันต้องการใช้ T like สำหรับ (Field f: T.class.getFields ()) {Column column = f.getAnnotation (Column.class); ถ้า (คอลัมน์! = null) System.out.println (column.columnName ()); }
ถึง

1
เป๊ะ! ฉันเองก็พยายามที่จะคิดออกเช่นกัน จะเป็นอย่างไรหากฉันต้องการมีตัวประมวลผลคำอธิบายประกอบที่ไม่จำเป็นต้องระบุชื่อคลาสอย่างชัดเจน สามารถเลือกขึ้นมาจากบริบทได้หรือไม่ 'นี้'??
5122014009

ฉันไม่แน่ใจว่าฉันเข้าใจว่าคุณสองคนต้องการอะไร โปรดถามเป็นคำถามใหม่พร้อมตัวอย่างเต็ม คุณสามารถเชื่อมโยงได้ที่นี่หากต้องการ
Cephalopod

3
ใช้Myclass.class.getDeclaredFields()เพื่อรับฟิลด์ส่วนตัว
q0re

มันได้ผลสำหรับฉัน ขอบคุณ. ฉันกำลังมองหาเขตข้อมูลส่วนตัวระดับซุปเปอร์คลาสดังนั้นฉันจึงใช้ clsName.getSuperclass () getDeclaredFields ()
Shashank

89

แน่นอนมันเป็น นี่คือตัวอย่างคำอธิบายประกอบ:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {

    String testText();
}

และตัวอย่างวิธีการที่มีคำอธิบายประกอบ:

class TestClass {

    @TestAnnotation(testText="zyx")
    public void doSomething() {}
}

และวิธีการตัวอย่างในคลาสอื่นที่พิมพ์ค่าของ testText:

Method[] methods = TestClass.class.getMethods();
for (Method m : methods) {
    if (m.isAnnotationPresent(TestAnnotation.class)) {
        TestAnnotation ta = m.getAnnotation(TestAnnotation.class);
        System.out.println(ta.testText());
    }
}

ไม่แตกต่างกันมากสำหรับคำอธิบายประกอบฟิลด์เช่นของคุณ

เชียร์ซ!


22

ฉันไม่เคยทำ แต่ดูเหมือนว่าReflectionจะให้สิ่งนี้ Fieldเป็นและดังนั้นจึงมีAnnotatedElement หน้านี้มีตัวอย่าง (คัดลอกด้านล่าง); ค่อนข้างตรงไปตรงมาหากคุณทราบคลาสของคำอธิบายประกอบและหากนโยบายคำอธิบายประกอบยังคงรักษาคำอธิบายประกอบไว้ที่รันไทม์ โดยปกติแล้วหากนโยบายการเก็บรักษาไม่เก็บคำอธิบายประกอบไว้ที่รันไทม์คุณจะไม่สามารถค้นหาในรันไทม์ได้getAnnotation

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

ตัวอย่างจากหน้านี้ :

import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Method;

@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
  String str();

  int val();
}

class Meta {
  @MyAnno(str = "Two Parameters", val = 19)
  public static void myMeth(String str, int i) {
    Meta ob = new Meta();

    try {
      Class c = ob.getClass();

      Method m = c.getMethod("myMeth", String.class, int.class);

      MyAnno anno = m.getAnnotation(MyAnno.class);

      System.out.println(anno.str() + " " + anno.val());
    } catch (NoSuchMethodException exc) {
      System.out.println("Method Not Found.");
    }
  }

  public static void main(String args[]) {
    myMeth("test", 10);
  }
}

6

อธิบายถึงคำตอบของ @Cephalopod หากคุณต้องการชื่อคอลัมน์ทั้งหมดในรายการคุณสามารถใช้ oneliner นี้:

List<String> columns = 
        Arrays.asList(MyClass.class.getFields())
              .stream()
              .filter(f -> f.getAnnotation(Column.class)!=null)
              .map(f -> f.getAnnotation(Column.class).columnName())
              .collect(Collectors.toList());

Objects.nonNull เพื่อรองรับ Java 8 อย่างสมบูรณ์ :) .filter (f -> nonNull (f.getAnnotation (Column.class)))
dehumanizer

4

ในขณะที่คำตอบทั้งหมดที่ให้มานั้นใช้ได้อย่างสมบูรณ์ แต่เราควรจำไว้ในไลบรารีการสะท้อนของ Googleสำหรับวิธีการสแกนคำอธิบายประกอบแบบทั่วไปและง่ายขึ้นเช่น

 Reflections reflections = new Reflections("my.project.prefix");

 Set<Field> ids = reflections.getFieldsAnnotatedWith(javax.persistence.Id.class);

3

คุณยังสามารถใช้ประเภททั่วไปในกรณีของฉันโดยคำนึงถึงทุกสิ่งที่กล่าวมาก่อนที่คุณจะสามารถทำสิ่งต่างๆเช่น:

public class SomeTypeManager<T> {

    public SomeTypeManager(T someGeneric) {

        //That's how you can achieve all previously said, with generic types.
        Annotation[] an = someGeneric.getClass().getAnnotations();

    }

}

จำไว้ว่าสิ่งนี้จะไม่เท่ากับ 100% กับ SomeClass.class.get (... ) ();

แต่ทำได้ทีเด็ด ...


3

ในกรณีทั่วไปคุณมีสิทธิ์เข้าถึงฟิลด์แบบส่วนตัวดังนั้นคุณจึงไม่สามารถใช้getFieldsในการสะท้อนกลับได้ แทนสิ่งนี้คุณควรใช้getDeclaredFields

ดังนั้นประการแรกคุณควรทราบว่าคำอธิบายประกอบคอลัมน์ของคุณมีการเก็บรักษารันไทม์หรือไม่:

@Retention(RetentionPolicy.RUNTIME)
@interface Column {
}

หลังจากนั้นคุณสามารถทำสิ่งนี้:

for (Field f: MyClass.class.getDeclaredFields()) {
   Column column = f.getAnnotation(Column.class);
       // ...
}

เห็นได้ชัดว่าคุณต้องการทำอะไรบางอย่างกับฟิลด์ - ตั้งค่าใหม่โดยใช้ค่าคำอธิบายประกอบ:

Column annotation = f.getAnnotation(Column.class);
if (annotation != null) {
    new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
        object,
        myCoolProcessing(
            annotation.value()
        )
    );
}

ดังนั้นโค้ดทั้งหมดจะมีลักษณะดังนี้:

for (Field f : MyClass.class.getDeclaredFields()) {
    Column annotation = f.getAnnotation(Column.class);
    if (annotation != null)
        new PropertyDescriptor(f.getName(), Column.class).getWriteMethod().invoke(
                object,
                myCoolProcessing(
                        annotation.value()
                )
        );
}

2

สำหรับคนไม่กี่คนที่ขอวิธีการทั่วไปสิ่งนี้จะช่วยคุณได้ (5 ปีต่อมา: p)

สำหรับตัวอย่างด้านล่างของฉันฉันกำลังดึงค่า RequestMapping URL จากเมธอดที่มีคำอธิบายประกอบ RequestMapping หากต้องการปรับสิ่งนี้สำหรับฟิลด์เพียงแค่เปลี่ยน

for (Method method: clazz.getMethods())

ถึง

for (Field field: clazz.getFields())

และสลับการใช้RequestMappingสำหรับคำอธิบายประกอบที่คุณต้องการอ่าน แต่ให้แน่ใจว่าคำอธิบายประกอบมี@Retention (RetentionPolicy.RUNTIME)

public static String getRequestMappingUrl(final Class<?> clazz, final String methodName)
{
    // Only continue if the method name is not empty.
    if ((methodName != null) && (methodName.trim().length() > 0))
    {
        RequestMapping tmpRequestMapping;
        String[] tmpValues;

        // Loop over all methods in the class.
        for (Method method: clazz.getMethods())
        {
            // If the current method name matches the expected method name, then keep going.
            if (methodName.equalsIgnoreCase(method.getName()))
            {
                // Try to extract the RequestMapping annotation from the current method.
                tmpRequestMapping = method.getAnnotation(RequestMapping.class);

                // Only continue if the current method has the RequestMapping annotation.
                if (tmpRequestMapping != null)
                {
                    // Extract the values from the RequestMapping annotation.
                    tmpValues = tmpRequestMapping.value();

                    // Only continue if there are values.
                    if ((tmpValues != null) && (tmpValues.length > 0))
                    {
                        // Return the 1st value.
                        return tmpValues[0];
                    }
                }
            }
        }
    }

    // Since no value was returned, log it and return an empty string.
    logger.error("Failed to find RequestMapping annotation value for method: " + methodName);

    return "";
}

0

หนึ่งในวิธีที่ฉันใช้:

protected List<Field> getFieldsWithJsonView(Class sourceClass, Class jsonViewName){
    List<Field> fields = new ArrayList<>();
    for (Field field : sourceClass.getDeclaredFields()) {
        JsonView jsonViewAnnotation = field.getDeclaredAnnotation(JsonView.class);
        if(jsonViewAnnotation!=null){
            boolean jsonViewPresent = false;
            Class[] viewNames = jsonViewAnnotation.value();
            if(jsonViewName!=null && Arrays.asList(viewNames).contains(jsonViewName) ){
                fields.add(field);
            }
        }
    }
    return fields;
}    
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.