It is necessary to call application code to maintain integrity (i.e. the guarantee of global program invariants), if you want to design classes for serialization that is agnostic to serialized format and that accounts for cases where not both sides of the communication are trusted. If program objects can be constructed from bits that arrive from external input that might not be trusted, some code needs to run to ensure that the objects maintain their invariants. Of course, you could say that objects cannot maintain any of their own invariants (that is the approach taken by Zig, where, unlike in Java, it is impossible to explicitly define, at the language level, an object that represents only prime integers), but that requires a very different language design, one that has not yet been proven to scale well (and one that isn't taken by Java specifically).