0

I am new to Java and trying to use Java reflection to set value to static final field in MuApiService using private int field modifiers from java.lang.reflect.Field. I found below example code and trying to compile in JAVA 11.

static void setFinalStatic(Field field, Object newValue) throws Exception {
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true); 
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, newValue);
    }

But below Exception is thrown in Java 11 . Field class has a field called "modifiers" Could not figure out what is the issue here . It works for ArrayList , Set etc .

 Time elapsed: 2.383 s  <<< FAILURE!

java.lang.NoSuchFieldException: modifiers
        at java.base/java.lang.Class.getDeclaredField(Class.java:2412)

Adding Code MyApiService.java

public class MyApiService extends RestApiService {



    private MyApiService(String baseURL, String user, String password) {
        super(baseURL, user, password);

    }


    /**
     * Singleton holder class for the MyApiService object
     */
    private static class SingletonHolder {
        private static final ACPConfig ACP_CONFIG = (ACPConfig) 
        private static final Config PLATFORM_AO_CONFIG = ACP_CONFIG.newConfig
                .getConfig(“def”)
                .getConfig("abc”);
        private static final String BASE_URL = PLATFORM_AO_CONFIG.getString("url");
        private static final String USER = PLATFORM_AO_CONFIG.getString("user");
        private static final String PASSWORD = PLATFORM_AO_CONFIG.getString("password");
        private static final MyApiService INSTANCE = new MyApiService(BASE_URL, USER, PASSWORD);
    }

    /**
     * Creates a singleton object of this class
     *
     * @return <code>MyApiService</code> singleton object
     */
    public static MyApiService getInstance() {
        return SingletonHolder.INSTANCE;
    }

Test.java

for (Class nclass : MyApiService.class.getDeclaredClasses()) {
    System.out.println("SimpleName is "+nclass.getSimpleName());
    if (nclass.getSimpleName().equals("SingletonHolder")) {
        sclass = nclass;

        System.out.println(" sclass is " + sclass.getSimpleName());

        for (Field field : sclass.getDeclaredFields()) {
            System.out.println("Field names are " + field.getName());
        }

        setFinalStatic(sclass.getDeclaredField("PLATFORM_AO_CONFIG"), null);
        setFinalStatic(sclass.getDeclaredField("USER "), null);
        setFinalStatic(sclass.getDeclaredField(" PASSWORD"), null);
        break;
    }
}
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Gajukorse
  • 147
  • 2
  • 11
  • Are you sure you need reflections? If something is `private` or `final` there's a reason for it (hopefully). And please post the class with the field. – akuzminykh Jul 22 '20 at 12:29
  • `Field` is a class from your project or from `java.lang.reflect`? If it's from `java.lang.reflect` - https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html , there is no field with name `modifiers`. – KunLun Jul 22 '20 at 12:30
  • Why are you trying to modify the finalness of a field at runtime? `final` only really makes sense at compile time anyway, so what do you hope to achieve? – Michael Jul 22 '20 at 12:34
  • I am modifying this for the sake of Unit testing . I am not doing in actual code but for mocking few fields in Unit test code – Gajukorse Jul 22 '20 at 12:50
  • 1
    Okay, this is a valid point but you still haven't posted the class. – akuzminykh Jul 22 '20 at 13:03
  • You want to use reflection on a class from the reflection API for unit testing? Okay, now it's getting weird again. – akuzminykh Jul 22 '20 at 13:55
  • Field is a class from java.lang.reflect. Sorry i have edited original qn its private int . I have even tried `for(Field modifiersField : Field.class.getDeclaredFields()){ System.out.println(modifiersField.getName());` Returns no elements. But on arraylist `for(Field modifiersField : ArrayList.class.getDeclaredFields()){ System.out.println(modifiersField.getName()); ` It gives below output . (Also in Arraylist `size` is private int ) `serialVersionUID DEFAULT_CAPACITY EMPTY_ELEMENTDATA DEFAULTCAPACITY_EMPTY_ELEMENTDATA elementData size` – Gajukorse Jul 22 '20 at 13:59
  • Reference : https://stackoverflow.com/questions/27552600/using-spock-to-mock-private-static-final-variables-in-java – Gajukorse Jul 22 '20 at 14:06

1 Answers1

0

A static final field can't be changed. It isn't because that's the rule (which it is) but because the field doesn't even exist anymore when your code is running. Anywhere it was used, the compiler just used the value. So these two blocks of code compile to exactly the same.

someObject.callSomeMethod(12);

and

static final int INCHES_PER_FOOT = 12;

someObject.callSomeMethod(INCHES_PER_FOOT);

So, basically, you're asking to use reflection to change the number 12 to something else. It doesn't even make sense to try.

Zag
  • 638
  • 4
  • 8
  • For completeness: this is only true for compile time constants (e.g. primitives, string literals, enum items), but not for objects used as constants. – Sean Patrick Floyd Jul 22 '20 at 22:49
  • @SeanPatrickFloyd, sort of. What is static is the pointer to the object, and that could not be changed to point to a different object (or to null). The object that it points to could be changed, but that isn't the same thing. – Zag Jul 24 '20 at 01:57
  • there is a distinction between compile-time constants and runtime constant. Here's the JLS definition of compile-time constants: https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.28 The compiler can optimize compile-time constants (as in your example), but not runtime constants. here's a decent intro into the topic: https://programmer.help/blogs/java-compile-time-constant-and-run-time-constant.html – Sean Patrick Floyd Jul 24 '20 at 21:02