Android project's unit test, which needs to test with different BuildConfig.DEBUG value
The BuildConfig class has DEBUG as final
public final class BuildConfig {
public static final boolean DEBUG = Boolean.parseBoolean("true");
}
This code works fine until update to java 17
ReflectionHelpers.setStaticField(BuildConfig.class, "DEBUG", true);
With java 17, now it gets error:
IllegalArgumentException: Cannot set the value of final field public static final boolean com.oath.mobile.shadowfax.adm.BuildConfig.DEBUG
java.lang.RuntimeException: java.lang.RuntimeException:
I think for the test case we can modify the code to use a function for the BuildConfig.DEBUG value. But ingeneral is there alternative to do modify a final field of a class?
As another has pointed out, there is this great answer. But the relevant part that should work specifically for you is through using the java.lang.invoke package to modify the DEBUG field in your test environment. I saw you mention this is for tests, so should be fair game. But I wouldn't use this in production.
Also note this likely will not work for Java 18+
import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class TestBuildConfig {
private static final VarHandle MODIFIERS;
static {
try {
var lookup = MethodHandles.privateLookupIn(Field.class, MethodHandles.lookup());
MODIFIERS = lookup.findVarHandle(Field.class, "modifiers", int.class);
} catch (IllegalAccessException | NoSuchFieldException ex) {
throw new RuntimeException(ex);
}
}
public static void main(String[] args) throws Exception {
var debugField = BuildConfig.class.getDeclaredField("DEBUG");
// make field non-final
MODIFIERS.set(debugField, debugField.getModifiers() & ~Modifier.FINAL);
// set field to new value
debugField.setAccessible(true);
debugField.set(null, false); // Change value as needed
// Conduct tests
System.out.println("DEBUG: " + BuildConfig.DEBUG);
}
}
Compile and run with:
javac TestBuildConfig.java
java --add-opens=java.base/java.lang.reflect=ALL-UNNAMED TestBuildConfig
This allows testing different BuildConfig.DEBUG values without changing the original source code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With