Java에서 주석 값을 읽을 수 있습니까?


99

이것은 내 코드입니다.

@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")의 값을 다른 클래스에서 읽을 수 있습니까?

답변:


122

예, 열 주석에 런타임 보존이있는 경우

@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 대신에 좀 더 일반적인 방법으로 만들 수 있습니다. (Field f : T.class.getFields ()) {Column column = f.getAnnotation (Column.class); if (column! = null) System.out.println (column.columnName ()); }
ATHER

1
바로 그거죠! 나는 그것을 알아 내기 위해 고군분투하고있다. 클래스 이름을 명시 적으로 제공 할 필요가없는 주석 프로세서를 사용하려면 어떻게해야합니까? 문맥에서 그것을 선택하도록 만들 수 있습니까? '이'??
5122014009 2014 년

두 분에게 필요한 것이 무엇인지 잘 모르겠습니다. 완전한 예를 들어 새로운 질문으로 물어보십시오. 원하는 경우 여기에 연결할 수 있습니다.
두족류

3
Myclass.class.getDeclaredFields()개인 필드를 가져 오는 데 사용
q0re

그것은 나를 위해 일했습니다. 감사. . 내가 clsName.getSuperclass ()를 사용, 그래서 내가 슈퍼 클래스의 private 필드를 찾고 있었다 getDeclaredFields ()
Shashank

88

당연하지. 다음은 샘플 주석입니다.

@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());
    }
}

귀하와 같은 필드 주석의 경우 크게 다르지 않습니다.

치어 즈!


21

나는 그것을 한 적이 없지만 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는 완전히 자바 8 : .filter 포용 (F를 -> 널 (null)이 아닌 (f.getAnnotation (Column.class)))
dehumanizer

4

지금까지 제공된 모든 답변은 완벽하게 유효하지만 주석 스캔에 대한보다 일반적이고 쉬운 접근 방식을 위해 Google Reflections 라이브러리 를 염두에 두어야합니다.

 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();

    }

}

이것은 SomeClass.class.get (...) ();과 100 % 동일하지 않다는 것을 기억하십시오.

하지만 트릭을 할 수 있습니다 ...


3

일반적인 경우에는 필드에 대한 개인 액세스 권한이 있으므로 리플렉션에 getFields 를 사용할 수 없습니다 . 대신에 getDeclaredFields 를 사용해야합니다.

따라서 먼저 Column 주석에 런타임 보존이 있는지 알아야합니다.

@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 주석이있는 메서드에서 RequestMapping URL 값을 가져옵니다. 이를 필드에 적용하려면

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.