Week 100 — What's the purpose of the `transient` keyword?

Question of the Week #100
What's the purpose of the transient keyword?
4 Replies
Eric McIntyre
Eric McIntyre5d ago
Serialization can be used to convert an object to a different format that can be stored or transferred and then be deserialized to a different format. For example, binary serialization (using ObjectOutputStream/ObjectInputStream) can do that automatically for classes implementing Serializable:
public class SomeDataClass implements Serializable {
private String someString;
private int someInt;
public SomeDataClass(String someString, int someInt){
this.someString = Objects.requireNonNull(someString);
this.someInt = someInt;
}
@Override
public String toString(){
return "SomeDataClass(someString=" + someString + ", someInt=" + someInt + ")";
}
}
public class SomeDataClass implements Serializable {
private String someString;
private int someInt;
public SomeDataClass(String someString, int someInt){
this.someString = Objects.requireNonNull(someString);
this.someInt = someInt;
}
@Override
public String toString(){
return "SomeDataClass(someString=" + someString + ", someInt=" + someInt + ")";
}
}
//write an object of that class to a file
SomeDataClass obj = new SomeDataClass("Hello World", 1337);
try(ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Path.of("object.dat")))) {
oos.writeObject(obj);//write the object to the ObjectOutputStream which serializes it and passes it to the underlying OutputStream
}
//write an object of that class to a file
SomeDataClass obj = new SomeDataClass("Hello World", 1337);
try(ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Path.of("object.dat")))) {
oos.writeObject(obj);//write the object to the ObjectOutputStream which serializes it and passes it to the underlying OutputStream
}
//read an object from that file
SomeDataClass obj;
try(ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Path.of("object.dat")))){
obj = (SomeDataClass)ois.readObject();//WARNING: Deserialization (of untrusted data) is dangerous
}
//read an object from that file
SomeDataClass obj;
try(ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Path.of("object.dat")))){
obj = (SomeDataClass)ois.readObject();//WARNING: Deserialization (of untrusted data) is dangerous
}
It should be noted that (de)serialization can lead to many issues including compatibility, construction of invalid objects (e.g. deserialized data is typically not validated on construction) and deserialization of untrusted data can lead to security vulnerabilities (from denial of service to remote code execution, see also the Javadoc of Serializable). Because of these issues, binary (de)serialization using ObjectInputStream/ObjectOutputStream should be avoided in most cases. The transient keyword can be used to exclude some fields from serialization. For example, if someInt is marked transient, it will not be included in the serialized form and will be 0 when deserialized.
public class SomeDataClass implements Serializable {
private String someString;
private transient int someInt;
public SomeDataClass(String someString, int someInt){
this.someString = Objects.requireNonNull(someString);
this.someInt = someInt;
}
@Override
public String toString(){
return "SomeDataClass(someString=" + someString + ", someInt=" + someInt + ")";
}
}
public class SomeDataClass implements Serializable {
private String someString;
private transient int someInt;
public SomeDataClass(String someString, int someInt){
this.someString = Objects.requireNonNull(someString);
this.someInt = someInt;
}
@Override
public String toString(){
return "SomeDataClass(someString=" + someString + ", someInt=" + someInt + ")";
}
}
Eric McIntyre
Eric McIntyre5d ago
Some third-party serialization libraries (like gson) also consider this keyword on fields and ignore transient fields during (de)serialization.
📖 Sample answer from dan1st
Eric McIntyre
Eric McIntyre5d ago
The transient keyword marks fields of a class as being excluded from the serialized state of an object. When a class is marked as serializable (implements the Serializable interface), the JVM will write the object's state during a serialization operation, such as with the ObjectOutputStream#writeObject​(Object obj) method. Fields marked as transient will be excluded from that mechanism. On the other side of the process, when objects of that class are deserialized (e.g. read with ObjectInputStream#readObject()), the transient fields will not be populated. The developer must account for these uninitialized fields by either setting them in the special readObject() method of the class, or by otherwise working around the empty value.
Eric McIntyre
Eric McIntyre5d ago
This keyword, along with Java's entire built-in serialization mechanism, is far less important today than when it was introduced to the language in JDK 1.1. The awkward semantics were the result of the limited language mechanisms that were available in the language at the time. Nowadays, there are much better tools for accomplishing the same thing. That said, the ecosystem does tend to respect the transient keyword or even adopt it for its own purposes. For instance, JPA will recognize transient fields in persistent classes and omit them from the persisted data. Lombok will ignore transient fields in its generated equals() & hashCode() implementations. Make sure to check the documentation of the frameworks and libraries you are using to see how transient fields are handled.
Submission from dangerously_casual
Want results from more Discord servers?
Add your server