Hm. First caevat: this is a BAD thing to do in production code. I've done it in tests (to switch jdbc driver) but it is not a good idea.
But: this is probably doable if you do it early enough. JavaC (assuming you use the Oracle one) does no optimization, it's all done by the the JIT. So, if you change it before the JIT does its magic then it should be fine.
In theory,you should be able to change the value after run-time optimization as well, since the JIT:ed code should be marked as no longer valid once you change the string but here I'm skating on very thin ice indeed.
This is (parts) of my test code.
I need to change the driver in this class:
class MysqlConnection {
private static final String DRIVER_NAME = "com.mysql.jdbc.Driver";
protected Connection instantiateNewConnection() {
try {
// The newInstance() call is a work around for some
// broken Java implementations
Class.forName(DRIVER_NAME).newInstance();
} catch (Exception ex) {
// handle the error
LOG.info("Class Exception: " + ex);
}
}
}
And I do it like this:
class DBOperation {
static {
Field f = MysqlConnection.class.getDeclaredField("DRIVER_NAME");
f.setAccessible(true);
f.set(f, LocalFlipper.HSQLDB_DRIVER);
}
}
This works. It IS possible to change final fields in java, it's just not a good idea.
First I modify the field in question, then I instantiate an instance and the DRIVET_NAME field contains the jdbc driver I want.
There seems to be some doubts about wether this will work or not, but I can assure you it does, try it out for yourselves.
@LouisWasserman: I've gone and javap:ed parts of the code:
Class.forName(DRIVER_NAME).newInstance();
corresponds to
28: ldc #16; //String com.mysql.jdbc.Driver
30: invokestatic #17; //Method java/lang/Class.forName(Ljava/lang/String;)Ljava/lang/Class;
33: invokevirtual #18; //Method java/lang/Class.newInstance:()Ljava/lang/Object;
As you can see, the String is not inlined. Besides, how do you inline an object (or complex type)? You can inline a reference (naturally). I agree that if we have code like
Class.forName("com.mysql.jdbc.Driver");
Then there is no way to access that string since we can't get a reference to it.