3

Is it possible to read an annotation element's value using reflection? I want to access the value of an element using a String of the element's name. Is this even possible?

Annotation:

import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Retention(RUNTIME)
@Target({CONSTRUCTOR, METHOD, TYPE})
public @interface TestCase {
    String brand1() default "";
    String brand2() default "";
    String brand3() default "";
}

Example usage:

@TestCase(brand1 = "1001", brand2 = "1101", brand3 = "1201")
@Test
public void testStep() {
    // run test here
}

I currently extract the element's value using a switch:

TestCase testCase = iInvokedMethod.getTestMethod().getConstructorOrMethod().getMethod().getAnnotation(TestCase.class);
switch (Brand brand) { // Brand is an enum value
    case BRAND1:
        testCaseId = testCase.brand1();
        break;
    case BRAND2:
        testCaseId = testCase.brand2();
        break;
    case BRAND3:
        testCaseId = testCase.brand3();
        break;
    default:
        testCaseId = "";
}

I'm looking to do something like this:

String sbrand = brand.toString.toLowerCase() // brand is an enum value
String s = iInvokedMethod.getTestMethod().getConstructorOrMethod().getMethod()
        .getAnnotation(TestCase.class).[iCantFigureThisPartOut](sbrand);

I tried:

String s = iInvokedMethod.getTestMethod().getConstructorOrMethod().getMethod()
        .getAnnotation(TestCase.class).getClass().getField("brand1").toString();

and I get a NoSuchFieldException:

java.lang.NoSuchFieldException: brand1
    at java.base/java.lang.Class.getField(Class.java:1956)

I've tried these to see if I could get anything:

Field[] fs = testCase.getClass().getFields();
Field[] dfs = testCase.getClass().getDeclaredFields();
Method[] ms = testCase.getClass().getMethods();
Method[] dms = testCase.getClass().getDeclaredMethods();

but when I iterate through and do a System.out.println(), the only thing that looks even remotely useful is the output from getDeclaredMethods():

public final boolean com.sun.proxy.$Proxy3.equals(java.lang.Object)
public final java.lang.String com.sun.proxy.$Proxy3.toString()
public final int com.sun.proxy.$Proxy3.hashCode()
public final java.lang.Class com.sun.proxy.$Proxy3.annotationType()
public final java.lang.String com.sun.proxy.$Proxy3.brand1()
public final java.lang.String com.sun.proxy.$Proxy3.brand2()
public final java.lang.String com.sun.proxy.$Proxy3.brand3()
  • 2
    Whatever you're trying to do, if you're using reflection, you're probably over-designing it. A more apt question might be, "How can change my solution to solve problem X without reflection?" And then describe what problem X actually is. – Brian Mar 09 '18 at 21:49

1 Answers1

3

Yes. You almost have it. Once you reach this part:

iInvokedMethod.getTestMethod().getConstructorOrMethod().getMethod()
    .getAnnotation(TestCase.class)

it gives you an object that inherits the TestCase annotation.

TestCase tc = iInvokedMethod.getTestMethod().getConstructorOrMethod().getMethod()
    .getAnnotation(TestCase.class);
String b1 = tc.brand1(); // returns the value "1001" from your example
String b2 = tc.brand2(); // returns the value "1101" from your example
String b3 = tc.brand3(); // returns the value "1201" from your example

edit: to add the other means @SotiriosDelimanolis said.

TestCase tc = iInvokedMethod.getTestMethod().getConstructorOrMethod().getMethod()
    .getAnnotation(TestCase.class);
Method fm = TestCase.class.getMethod("brand1"); // or brand2 or a variable
String brand = (String) fm.invoke(tc); // returns the value "1001" from your example
coladict
  • 4,799
  • 1
  • 16
  • 27