Forbidden Java actions: updating final and static final fields

by Mikhail Vorontsov

This article will discuss how you can update final or static final fields in Java. This is not allowed on the Java language level, but surprisingly, standard JDK classes will make it possible for you. Of course, we won’t forget a best Java hacker friend – sun.misc.Unsafe class from Oracle JDK. This is a second article in the “Forbidden Java actions” series started with Forbidden Java actions: object assignments, type conversions etc on the low level in Java.

Updating final or private fields

This is a simple trick. All you have to know about is a java.lang.reflect.AccessibleObject.setAccessible(boolean) method. If a field or method can not be accessed by Java language means in the current context (for example, you want to access a private field or method) – use this method with argument = true to obtain reflection access to that field or method. Unfortunately, this method is a subject of security checks, so it may be forbidden by a security manager in many enterprise server environments.

The following program will update a private final field of another class. It will print 20, despite the fact that a final field was initialized with 10 in the constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class FinalPrivateField {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        final A instance = new A( 10 );
        B.updateA( instance, 20 );
        System.out.println( instance.getField() );
    }
 
    public static class A
    {
        private final int m_field;
 
        public A( final int field ) {
            m_field = field;
        }
 
        public int getField() {
            return m_field;
        }
    }
 
    public static class B
    {
        public static void updateA( final A other, final int newValue ) throws NoSuchFieldException, IllegalAccessException
        {
            final Field fieldA = A.class.getDeclaredField( "m_field" );
            fieldA.setAccessible( true );
            fieldA.setInt( other, newValue );
        }
    }
}
public class FinalPrivateField {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        final A instance = new A( 10 );
        B.updateA( instance, 20 );
        System.out.println( instance.getField() );
    }

    public static class A
    {
        private final int m_field;

        public A( final int field ) {
            m_field = field;
        }

        public int getField() {
            return m_field;
        }
    }

    public static class B
    {
        public static void updateA( final A other, final int newValue ) throws NoSuchFieldException, IllegalAccessException
        {
            final Field fieldA = A.class.getDeclaredField( "m_field" );
            fieldA.setAccessible( true );
            fieldA.setInt( other, newValue );
        }
    }
}

Updating final static fields

This trick will be slightly more complicated. Now we need to update a static final field (it doesn’t matter if it is public or private). Such fields are usually used as constant definitions in Java code. This has a consequence: Java Language Specification (15.28) says that static final fields of primitive types or type String initialized with compile time constants (either constants or expressions which are evaluated at compile time) are inlined at all code points where such fields are referenced. It makes updates to static final primitive or String fields nearly useless. The only way to get their new value will be via reflection.

You can not update static final fields the same way as just private or final: you will get an exception like this:

java.lang.IllegalAccessException: Can not set static final java.lang.String field FIELD_NAME_HERE to java.lang.String

All you need to do now is to apply the same trick twice. First of all, make the field itself accessible. Then remove ‘final’ modifier from this field (you may return it back after update if you wish). In order to do this, you’ll have to update java.lang.reflect.Field.modifiers field. Obtain a Field object for that field, make it accessible and update it.

The following classes will demonstrate you how to update 2 static final fields – one of type String and another of type Integer. Updates to the String field will be visible only via reflection. This example contains 2 separate classes: SafeKlass defines 2 private static final fields and getters for them; FinalPrivateStaticField class contains update logic.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.lang.reflect.Field;
 
public class SafeKlass {
    private static final String CONSTANT = "You can not change me, I'm a constant expression!";
    private static final Integer NOT_SO_CONSTANT = 10;
 
    public static String getConstant()
    {
        return CONSTANT;
    }
 
    public static String getConstantReflection()
    {
        try {
            final Field fld = SafeKlass.class.getDeclaredField( "CONSTANT" );
            return (String) fld.get( null );
        } catch (NoSuchFieldException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
    }
 
    public static int getNotSoConstant()
    {
        return NOT_SO_CONSTANT;
    }
}
import java.lang.reflect.Field;

public class SafeKlass {
    private static final String CONSTANT = "You can not change me, I'm a constant expression!";
    private static final Integer NOT_SO_CONSTANT = 10;

    public static String getConstant()
    {
        return CONSTANT;
    }

    public static String getConstantReflection()
    {
        try {
            final Field fld = SafeKlass.class.getDeclaredField( "CONSTANT" );
            return (String) fld.get( null );
        } catch (NoSuchFieldException e) {
            return null;
        } catch (IllegalAccessException e) {
            return null;
        }
    }

    public static int getNotSoConstant()
    {
        return NOT_SO_CONSTANT;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
 
public class FinalPrivateStaticField {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        {
            //try updating a String field first
            Field field = SafeKlass.class.getDeclaredField( "CONSTANT" );
            field.setAccessible( true );
 
            //'modifiers' - it is a field of a class called 'Field'. Make it accessible and remove
            //'final' modifier for our 'CONSTANT' field
            Field modifiersField = Field.class.getDeclaredField( "modifiers" );
            modifiersField.setAccessible( true );
            modifiersField.setInt( field, field.getModifiers() & ~Modifier.FINAL );
 
            //it updates a field, but it was already inlined during compilation...
            field.set( null, "I was updated!" );
 
            //this method call will return an inlined value
            System.out.println( SafeKlass.getConstant() );
            //the only way to actually see an updated value is again via reflection
            System.out.println( SafeKlass.getConstantReflection() );
        }
        {
            //now try to update not constant expression type field
            Field field = SafeKlass.class.getDeclaredField( "NOT_SO_CONSTANT" );
            field.setAccessible( true );
 
            //'modifiers' - it is a field of a class called 'Field'. Make it accessible and remove
            //'final' modifier for our 'CONSTANT' field
            Field modifiersField = Field.class.getDeclaredField( "modifiers" );
            modifiersField.setAccessible( true );
            modifiersField.setInt( field, field.getModifiers() & ~Modifier.FINAL );
 
            //this update should actually work
            field.set( null, -20 );
 
            System.out.println( SafeKlass.getNotSoConstant() );
        }
    }
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class FinalPrivateStaticField {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        {
            //try updating a String field first
            Field field = SafeKlass.class.getDeclaredField( "CONSTANT" );
            field.setAccessible( true );

            //'modifiers' - it is a field of a class called 'Field'. Make it accessible and remove
            //'final' modifier for our 'CONSTANT' field
            Field modifiersField = Field.class.getDeclaredField( "modifiers" );
            modifiersField.setAccessible( true );
            modifiersField.setInt( field, field.getModifiers() & ~Modifier.FINAL );

            //it updates a field, but it was already inlined during compilation...
            field.set( null, "I was updated!" );

            //this method call will return an inlined value
            System.out.println( SafeKlass.getConstant() );
            //the only way to actually see an updated value is again via reflection
            System.out.println( SafeKlass.getConstantReflection() );
        }
        {
            //now try to update not constant expression type field
            Field field = SafeKlass.class.getDeclaredField( "NOT_SO_CONSTANT" );
            field.setAccessible( true );

            //'modifiers' - it is a field of a class called 'Field'. Make it accessible and remove
            //'final' modifier for our 'CONSTANT' field
            Field modifiersField = Field.class.getDeclaredField( "modifiers" );
            modifiersField.setAccessible( true );
            modifiersField.setInt( field, field.getModifiers() & ~Modifier.FINAL );

            //this update should actually work
            field.set( null, -20 );

            System.out.println( SafeKlass.getNotSoConstant() );
        }
    }
}

This program will print:

You can not change me, I'm a constant expression!
I was updated!
-20

It shows that direct field access is inlined (first line), but we can still confirm an update via reflection (second line). Updating a non-constant expression is easier, as we can see by the value on the third line (which was originally equal to 10).

Updating final and static final fields using sun.misc.Unsafe

Two previously discussed methods of updating a final field used only official JDK capabilities. Now let’s look at the dirty trick – we will use sun.misc.Unsafe in order to make the same updates. As you will see, we will end up with a shorter code than in previous examples.

The key concept you should understand about updating Java objects via sun.misc.Unsafe is that all Java fields could be addressed by their offsets from the address of the object. Same applies to static fields – their offset is calculated from the Class object. You can read more about Java memory layout in Memory introspection using sun.misc.Unsafe and reflection article.

In order to update a field, you will need to use one of Unsafe put* methods. Let’s look at putInt method for example:

1
public native  void putInt(Object base, long offset, int value)
public native  void putInt(Object base, long offset, int value)

First argument is a base object – the object you update for instance fields and the Class object for static fields (static case will be discussed below in more details). Second argument is a field offset – use Unsafe.objectFieldOffset( Field ) for instance fields and Unsafe.staticFieldOffset for static fields. The third argument is the value to set.

As it was written above, the base object for static fields is their Class object. Unfortunately, it is not documented. Instead you are advised to use public Object Unsafe.staticFieldBase( Field ) method for obtaining a base object for static fields.

The following class will update both static and instance fields using Unsafe methods. We will reuse SafeKlass for static fields update.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class FinalUnsafeFields {
    private static final Unsafe unsafe;
    static
    {
        try
        {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe)field.get(null);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }
 
 
    public static void main(String[] args) throws NoSuchFieldException {
        updateFinal();
        updateFinalStatic();
    }
 
    private static void updateFinalStatic() throws NoSuchFieldException {
        System.out.println( "Original static final value = " + SafeKlass.getNotSoConstant() );
        //we need a field to update
        final Field fieldToUpdate = SafeKlass.class.getDeclaredField( "NOT_SO_CONSTANT" );
        //this is a 'base'. Usually a Class object will be returned here.
        final Object base = unsafe.staticFieldBase( fieldToUpdate );
        //this is an 'offset'
        final long offset = unsafe.staticFieldOffset( fieldToUpdate );
        //actual update
        unsafe.putObject( base, offset, 145 );
        //ensure the value was updated
        System.out.println( "Updated static final value = " + SafeKlass.getNotSoConstant() );
    }
 
    private static void updateFinal() throws NoSuchFieldException {
        final JustFinal obj = new JustFinal( 10 );
        //ensure we can see an original value
        System.out.println( "Original value = " + obj.getField() );
        //obtain an updated field
        final Field fieldToUpdate = JustFinal.class.getDeclaredField( "m_field" );
        //get unsafe offset to this field
        final long offset = unsafe.objectFieldOffset( fieldToUpdate );
        //actual update
        unsafe.putInt( obj, offset, 20 );
        //ensure update was successful
        System.out.println( "Updated value = " + obj.getField() );
    }
 
    private static final class JustFinal
    {
        private final int m_field;
 
        public JustFinal(int field) {
            m_field = field;
        }
 
        public int getField() {
            return m_field;
        }
    }
}
public class FinalUnsafeFields {
    private static final Unsafe unsafe;
    static
    {
        try
        {
            Field field = Unsafe.class.getDeclaredField("theUnsafe");
            field.setAccessible(true);
            unsafe = (Unsafe)field.get(null);
        }
        catch (Exception e)
        {
            throw new RuntimeException(e);
        }
    }


    public static void main(String[] args) throws NoSuchFieldException {
        updateFinal();
        updateFinalStatic();
    }

    private static void updateFinalStatic() throws NoSuchFieldException {
        System.out.println( "Original static final value = " + SafeKlass.getNotSoConstant() );
        //we need a field to update
        final Field fieldToUpdate = SafeKlass.class.getDeclaredField( "NOT_SO_CONSTANT" );
        //this is a 'base'. Usually a Class object will be returned here.
        final Object base = unsafe.staticFieldBase( fieldToUpdate );
        //this is an 'offset'
        final long offset = unsafe.staticFieldOffset( fieldToUpdate );
        //actual update
        unsafe.putObject( base, offset, 145 );
        //ensure the value was updated
        System.out.println( "Updated static final value = " + SafeKlass.getNotSoConstant() );
    }

    private static void updateFinal() throws NoSuchFieldException {
        final JustFinal obj = new JustFinal( 10 );
        //ensure we can see an original value
        System.out.println( "Original value = " + obj.getField() );
        //obtain an updated field
        final Field fieldToUpdate = JustFinal.class.getDeclaredField( "m_field" );
        //get unsafe offset to this field
        final long offset = unsafe.objectFieldOffset( fieldToUpdate );
        //actual update
        unsafe.putInt( obj, offset, 20 );
        //ensure update was successful
        System.out.println( "Updated value = " + obj.getField() );
    }

    private static final class JustFinal
    {
        private final int m_field;

        public JustFinal(int field) {
            m_field = field;
        }

        public int getField() {
            return m_field;
        }
    }
}

The output of this program proves that all updates were successful:

Original value = 10
Updated value = 20
Original static final value = 10
Updated static final value = 145

Summary

  • If you want to update a private and/or final field using Java reflection – make a Method or Field accessible via Method/Field.setAccessible( true ) and then set a new field value.
  • If you want to update a final static field using reflection – you will need to make 2 steps: make the field itself accessible and then make accessible modifiers field of Field you want to update and remove final flag from Field modifiers. Such updates to static final fields of primitive/String initialized with complile-time expressions will not be visible to clients, because static fields initialized with constant expressions (JLS 15.28) are inlined.
  • You may also update final and static final fields using sun.misc.Unsafe. Use Unsafe.putN( base, offset, newValue ) methods for updates. base is the owner of a field for instance fields and the Class object for static fields. offset could be obtained with Unsafe.objectFieldOffset( Field ) for instance fields and Unsafe.staticFieldOffset( Field ) for static fields.