JDK-5103437 : (reflect) Can set a final instance variable via reflection if setAccessible(true
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang:reflect
  • Affected Version: 5.0
  • Priority: P3
  • Status: Closed
  • Resolution: Duplicate
  • OS: linux
  • CPU: x86
  • Submitted: 2004-09-16
  • Updated: 2012-09-28
  • Resolved: 2004-09-16
Related Reports
Duplicate :  
Relates :  
Description

Name: rmT116609			Date: 09/16/2004


FULL PRODUCT VERSION :
java version "1.5.0-rc"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-rc-b63)
Java HotSpot(TM) Client VM (build 1.5.0-rc-b63, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
SuSe 9.1
Linux 2.6.4-52-default

A DESCRIPTION OF THE PROBLEM :
I am using the reflection API to set a value of an instance variable.

I have a unit test that basically ends up using the reflection API (Field.set()) to set a final instance variable. I expect an exception is thrown and that the value is never set. However, the value is actually set and no exception is thrown.

In 1.4, 1.4.1 and 1.4.2 and 1.5 Beta 1, my unit tests passed. starting with 1.5 beta 2, my unit test began to fail and it still fails under 1.5 RC

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a class with a final instance String variable and set the value to "something".

Use the Field.set() method to try and set the value.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
An exception should be thrown and the value should not be set.
ACTUAL -
An exception isn't thrown and the value is actually set.

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import java.lang.reflect.Field;
              
public class SetableFinalTest{

    protected final String finalString = new String("final String");
    protected final int finalInt = 0;
    protected final static String FAIL = "FAIL: ";
    protected final static String WARN = "WARN: ";
    protected final static String PASS = "PASS: ";

    public static void main (String args[]) {
        SetableFinalTest t = new SetableFinalTest();
        Class c = t.getClass();
        try{
            Field f = c.getDeclaredField("finalString");
            f.setAccessible(true);
            f.set(t, "new String value");
        }catch(NoSuchFieldException nsfe){
            printMsg(FAIL, "No field found");
        }catch(IllegalAccessException iae){
            printMsg(PASS, "wasn't able to set the value of a final String variable");
        }
        if (t.finalString.equals("new String value")) {
            printMsg(FAIL, "was able to set the value of a final String variable");
        }
        boolean noExceptionThrown = true;
        try{
            Field f = c.getDeclaredField("finalInt");
            f.setAccessible(true);
            f.setInt(t, 1);
        }catch(NoSuchFieldException nsfe){
            printMsg(FAIL, "No field found");
        }catch(IllegalAccessException iae){
            printMsg(PASS, "wasn't able to set the value to a final primative variable");
            noExceptionThrown = false;
        }
        if (t.finalInt == 1) {
            printMsg(FAIL, "was able to set the value to a final primative variable");
        }else{
            printMsg(PASS, "wasn't able to set the value to a final primative variable");
            if (noExceptionThrown) {
                printMsg(WARN, "An expected IllegalAccessException was not thrown.");
            }
        }
    }


    public static void printMsg(String status, String msg){
        System.out.println(status + msg);
    }

}

---------- END SOURCE ----------

Test Results:

With 5.0 RC:
-------------

C:\>javac SetableFinalTest.java

C:\>java SetableFinalTest
FAIL: was able to set the value of a final String variable
PASS: wasn't able to set the value to a final primative variable
WARN: An expected IllegalAccessException was not thrown.

With 1.4.2_05, tiger-beta:
---------------------------

C:\>javac SetableFinalTest.java

C:\>java SetableFinalTest
PASS: wasn't able to set the value of a final String variable
PASS: wasn't able to set the value to a final primative variable
PASS: wasn't able to set the value to a final primative variable


CUSTOMER SUBMITTED WORKAROUND :
Use 1.4.2_05 or 1.5 beta 1

Release Regression From : 1.4.2_05
The above release value was the last known release where this 
bug was known to work. Since then there has been a regression.

(Incident Review ID: 302197) 
======================================================================

Comments
EVALUATION This is the expected behaviour and a duplicate of previously reported bug 5059911. Here's the evaluation from that bug: After much deliberation [involving reflection owners/experts, the JSR-133 expert group, and hotspot engineers], bug 5044412 modified the specification of Field.set to allow modification of the field if it is non-static and setAccessible(true) has succeeded. The specification of Field.set contains more details. In making this change, we reverted to the behaviour which existed prior to jdk1.3. -- iag@sfbay 2004-09-16
16-09-2004