Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
140 views
in Technique[技术] by (71.8m points)

java - UnsupportedEncodingException is not getting thrown, if we change final property value using reflection

package com.java.random.practice;
    
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
    
public class App 
{
    private static final String ENCODING = "\UTF-8";
    public static void main( String[] args ) throws UnsupportedEncodingException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
        {      
            URLEncoder.encode("anyValue", ENCODING);
        }
}

Above code throws exception UnsupportedEncodingException when use "" with encoding but when we use Reflection to modify the value then it does not show any exception, please see the below code:

package com.java.random.practice;
    
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URLEncoder;
    
public class App 
{
    private static final String ENCODING = "UTF-8";
    public static void main( String[] args ) throws UnsupportedEncodingException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
        {      
            App app=new App(); 
            Field field = app.getClass().getDeclaredField("ENCODING");
            field.setAccessible(true); 
            Field modifiersField =
            Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true); modifiersField.setInt(field,
            field.getModifiers() & ~Modifier.FINAL); field.set(null, "\UTF-8");
             
            String s= URLEncoder.encode("anyValue", ENCODING);
            System.out.println(s);
        }
    }

Why this kind of strange behavior?

question from:https://stackoverflow.com/questions/65844749/unsupportedencodingexception-is-not-getting-thrown-if-we-change-final-property

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Values of compilation time constants are inlined by compiler.

What does it mean?
Lets say there is private static final String STR = "Foo";. Here we are sure (using standard language rules, without including reflection since it is a tool that breaks all guarantees language enforces, like: preventing accessing private members, modifying final, etc.) that value of STR should be always "Foo" and that information is also known at compilation time.

This allows compiler to optimize code like System.out.println(STR); and remove the need to lookup value of STR but instead use it directly which will produce same bytecode as if we would write System.out.println("Foo"); (since value is known to compiler and "theoretically" always the same).

So even if we use reflection and reassign new value to STR it will not affect bytecode which represents System.out.println("Foo"); since it no longer depends on STR.

In your case

String s= URLEncoder.encode("anyValue", ENCODING);

will be compiled as if you would write it as

String s= URLEncoder.encode("anyValue", "UTF-8");

(since private static final String ENCODING = "UTF-8"; value of ENCODINT is "UTF-8" and that is inlined in places where ENCODINT is being used). So even if you assign new value to ENCODINT (here "UTF-8") it can't affect bytecode which represents URLEncoder.encode("anyValue", "UTF-8") since it doesn't use/refer to ENCODING.

If you want to prevent inlining don't make ENCODING a compilation time constant. In other words ensure that assigned value will need to be "calculated" at runtime. For instance you can use private static final String ENCODING = "UTF-8".substring(0);.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...