Skip to content

Instantly share code, notes, and snippets.

@szarnekow
Last active December 10, 2015 23:28
Show Gist options
  • Save szarnekow/4509688 to your computer and use it in GitHub Desktop.
Save szarnekow/4509688 to your computer and use it in GitHub Desktop.
Modify final fields
public class Doh {
public static void main(String[] args) throws Exception {
Person p = new Person("Name");
setName(p, "New Name");
setDefault("Bob");
System.out.println(p.getName());
System.out.println(Person.DEFAULT);
}
/**
* Allows to change the state of an immutable instance. Huh?!?
*/
private static void setName(Person p, String newName) throws Exception {
Field nameField = p.getClass().getDeclaredField("name");
setValue(p, nameField, newName);
}
/**
* Allows to change the state of final statics. Huh?!?
*/
private static void setDefault(String newDefault) throws Exception {
Field staticField = Person.class.getDeclaredField("DEFAULT");
setValue(null, staticField, newDefault);
}
/**
*
* Set the value of a field reflectively.
*/
protected static void setValue(Object owner, Field field, Object value) throws Exception {
makeModifiable(field);
field.set(owner, value);
}
/**
*
* Force the field to be modifiable and accessible.
*/
protected static void makeModifiable(Field nameField) throws Exception {
nameField.setAccessible(true);
int modifiers = nameField.getModifiers();
Field modifierField = nameField.getClass().getDeclaredField("modifiers");
modifiers = modifiers & ~Modifier.FINAL;
modifierField.setAccessible(true);
modifierField.setInt(nameField, modifiers);
}
}
/**
* An immutable data class.
*/
class Person {
// avoid inlining by calling newString("unnamed")
public static final String DEFAULT = new String("unnamed");
private final String name;
public Person(String name) {
this.name = name == null ? DEFAULT : name;
}
public String getName() {
return name;
}
}
/**
* Force the field to be modifiable and accessible.
*/
protected static void makeModifiable(Field nameField) throws Exception {
nameField.setAccessible(true);
int modifiers = nameField.getModifiers();
Field modifierField = nameField.getClass().getDeclaredField("modifiers");
modifiers = modifiers & ~Modifier.FINAL;
modifierField.setAccessible(true);
modifierField.setInt(nameField, modifiers);
}
/**
* Force the field to accessible.
*/
protected static void makeModifiable(Field nameField) throws Exception {
nameField.setAccessible(true);
}
/**
* An immutable data class.
*/
class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment