Java에서 기본값을 사용하여 Annotation 인스턴스 생성
-
06-07-2019 - |
문제
다음 주석의 인스턴스를 어떻게 생성합니까(모든 필드가 기본값으로 설정됨)?
@Retention( RetentionPolicy.RUNTIME )
public @interface Settings {
String a() default "AAA";
String b() default "BBB";
String c() default "CCC";
}
나는 노력했다 new Settings()
, 하지만 그건 작동하지 않는 것 같습니다 ...
해결책 2
인스턴스를 만들 수는 없지만 최소한 기본값을 얻습니다.
Settings.class.getMethod("a").getDefaultValue()
Settings.class.getMethod("b").getDefaultValue()
Settings.class.getMethod("c").getDefaultValue()
그런 다음 동적 프록시를 사용하여 기본값을 반환 할 수 있습니다. 내가 알 수있는 한, Java 자체에 의해 주석이 처리되는 방식도 있습니다.
class Defaults implements InvocationHandler {
public static <A extends Annotation> A of(Class<A> annotation) {
return (A) Proxy.newProxyInstance(annotation.getClassLoader(),
new Class[] {annotation}, new Defaults());
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.getDefaultValue();
}
}
Settings s = Defaults.of(Settings.class);
System.out.printf("%s\n%s\n%s\n", s.a(), s.b(), s.c());
다른 팁
인스턴스를 만들려면 다음을 구현하는 클래스를 만들어야합니다.
java.lang.Annotation
- 그리고 당신이 "시뮬레이션"하고 싶은 주석
예를 들어: public class MySettings implements Annotation, Settings
그러나 당신은 특별한주의를 기울여야합니다 옳은 구현 equals
그리고 hashCode
에 따르면 Annotation
상호 작용.http://download.oracle.com/javase/1.5.0/docs/api/java/lang/annotation/annotation.html
이것을 계속해서 구현하고 싶지 않다면 javax.enterprise.util.annotationliteral 수업. 이는 CDI (컨텍스트 종속성 주입) -api의 일부입니다.(@see 코드)
기본값을 얻으려면 Adrian이 설명하는 방식을 사용할 수 있습니다.Settings.class.getMethod("a").getDefaultValue()
나는 만족스러운 결과로 아래에서 컴파일하고 실행했습니다.
class GetSettings {
public static void main (String[] args){
@Settings final class c { }
Settings settings = c.class.getAnnotation(Settings.class);
System.out.println(settings.aaa());
}
}
같은 문제가 있었기 때문에 다음과 같이 해결했습니다.
public static FieldGroup getDefaultFieldGroup() {
@FieldGroup
class settring {
}
return settring.class.getAnnotation(FieldGroup.class);
}
메소드와 함께 사용하는 경우 :
@Settings
public void myMethod() {
}
이제 주석이 기본값으로 초기화됩니다.
이는 Sun/Oracle Java 5,6,7,8에서 작동합니다.(그러나 관련된 sun 클래스로 인해 Java 9에서는 잠재적으로 중단될 수 있습니다.)//편집 OpenJDK 9b59에서 여전히 작동하는지 확인했습니다.
package demo;
import sun.reflect.annotation.AnnotationParser;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class AnnotationProxyExample
{
public static void main(String[] args)
{
System.out.printf("Custom annotation creation: %s%n",
createAnnotationInstance(Collections.singletonMap("value", "required"), Example.class));
System.out.printf("Traditional annotation creation: %s%n",
X.class.getAnnotation(Example.class));
}
private static <A extends Annotation> A createAnnotationInstance(Map<String, Object> customValues, Class<A> annotationType)
{
Map<String, Object> values = new HashMap<>();
//Extract default values from annotation
for (Method method : annotationType.getDeclaredMethods())
{
values.put(method.getName(), method.getDefaultValue());
}
//Populate required values
values.putAll(customValues);
return (A) AnnotationParser.annotationForMap(annotationType, values);
}
@Example("required")
static class X
{
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Example
{
String value();
int foo() default 42;
boolean bar() default true;
}
}
산출:
Custom annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
Traditional annotation creation: @demo.AnnotationProxyExample$Example(bar=true, foo=42, value=required)
대체 솔루션이 있습니다. Settings
수업:
@Retention( RetentionPolicy.RUNTIME )
public @interface Settings {
String DEFAULT_A = "AAA";
String DEFAULT_B = "BBB";
String DEFAULT_C = "CCC";
String a() default DEFAULT_A;
String b() default DEFAULT_B;
String c() default DEFAULT_C;
}
그런 다음 간단히 참조 할 수 있습니다 Settings.DEFAULT_A
(예, 더 나은 이름이 도움이 될 것입니다!).