jOOQ / jOOR

jOOR - Fluent Reflection in Java jOOR is a very simple fluent API that gives access to your Java Class structures in a more intuitive way. The JDK's reflection APIs are hard and verbose to use. Other languages have much simpler constructs to access type meta information at runtime. Let us make Java reflection better.
http://www.jooq.org/products
Apache License 2.0
2.81k stars 376 forks source link

Fail to set private static final variable #39

Closed oliveeyay closed 6 years ago

oliveeyay commented 7 years ago

Hello,

First of all, thank you for the library, it's really useful :)

I found an issue when I want to reflect on a private final static variable (the worst case ^^), Joor throws a: org.joor.ReflectException: java.lang.IllegalAccessException: Can not set static final boolean field com.ogoutay.robomocki3.BuildConfig.DEBUG to java.lang.Boolean

If I use my own Kotlin extension on top of your library, it works well:

Reflect.setFinalStatic(name: String, newValue: Any) {
    val field = this.get<Class<*>>().getDeclaredField(name)

    field.isAccessible = true
    val modifiersField = Field::class.java.getDeclaredField("modifiers")
    modifiersField.isAccessible = true
    modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv())

    field.set(null, newValue)
}

Do you know where the problem could come from?

Thank you in advance

Cheers,

Olivier

lukaseder commented 7 years ago

Thanks for your report and for documenting the workaround. Would you mind showing a bit of code that helps reproduce the original case?

oliveeyay commented 7 years ago

Hello @lukaseder

Thank you for your answer. I have a small example Android project using your library at https://github.com/olivierg13/RobolectricMockitoGradle3

If you replace the setFinalStatic by set in kotlin and java, you will see the error appearing.

Thank you in advance :)

lukaseder commented 7 years ago

Sorry for the delay. I can't see how your version of the code and jOOR's really differ apart from calling set(null, value) rather than set(object, value). Both should be viable, though, and neither works on my side. What JDK version are you using?

oliveeyay commented 7 years ago

Hello @lukaseder No problem :) I remember while writing the solution that the order of the private / final modifiers mattered, but I'm not 100% sure that's the problem.

I'm running this code as part of a Robolectric test (Android), that should use my machine JVM. java version "1.8.0_131" Java(TM) SE Runtime Environment (build 1.8.0_131-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode)

Thank you for looking into it :)

lukaseder commented 7 years ago

Thanks for the update. You cannot modify the private modifier order, but static / final can be switched, but I really doubt that this has any impact on bytecode...

I currently still can't reproduce a working version of the code, I'm afraid.

BaoBaoJianqiang commented 6 years ago

I have the same problem, I find there is no field "modifiers" in the class Field, My version is Android-25. Please help to check the root cause

BaoBaoJianqiang commented 6 years ago

Today, I find the root cause for this issue, in Java SDK, it works, but in Android SDK, there is also a Filed class but hasn't "modifiers" fields, that's why Android dev find this issue, but the jOOR author can't reproduce in his java environment.

lukaseder commented 6 years ago

Hi @BaoBaoJianqiang: I'm not sure if it's the same issue because clearly, this problem here isn't about Android. Would you mind creating a new, separate issue instead? I'll be very happy to look into this problem, then.