I was asked this question in an interview. The interviewer wanted to know how to make an object immutable. and then he asked what if I serialise this object - will it break immutability? If yes, how do I prevent it? Can anyone please help me understand this?
相关问题
- Delete Messages from a Topic in Apache Kafka
- Jackson Deserialization not calling deserialize on
- How to maintain order of key-value in DataFrame sa
- StackExchange API - Deserialize Date in JSON Respo
- Difference between Types.INTEGER and Types.NULL in
You should read Effective Java written by Joshua Bloch. There is whole chapter about security issues connected with serialization and advices how to design your class properly.
In few words: you should learn about readObject and readResolve methods.
More detailed answer: Yes serialization can break immutability.
Let's assume you have class Period (it's example from Joshua's book):
It looks great. It's immutable (you can't change start and end after initialization), elegant, small, threadsafe etc.
But...
You have to remember that serialization is another way of creating objects (and it is not using constructors). Objects are build from byte stream.
Consider scenario when someone (attacker) change your serialization byte array. If he does such thing he could break your condition about start < end. Moreover there is possibility that attacker will put in stream (passed to deserialization method) reference to his Date object (which is mutable and Period class immutability will be completely destructed).
The best defense is not using serialization if you don't have to. If you have to serialize your class use Serialization Proxy pattern.
Edit (at kurzbot request): If you want to use Serialization Proxy you have to add static inner class inside Period. This class objects will be used for serialization instead of Period class objects.
In Period class write two new methods:
First method replace default serialized Period object with SerializationProxy object. Second guarantee that attacker won't use standard readObject method.
You should write writeObject method for SerializationProxy so you can use:
In that case you are using only public API and have certainty that Period class will remain immutably.
The dirt-simple answer is
The field foo will equals "foo" if the object is newly created, but will be null when deserialized (and without resorting to dirty tricks, you won't be able to assign it).
When you serialize an object graph that has multiple references to the same object, the serializer notes this fact, so that the deserialized object graph has the same structure.
For example,
will print
true
, and if you serialized and deserializedtwoArrays
then you would get the same result instead of each element of the array being a different object as inYou can exploit this support for reference sharing to craft bytes after a serialized entry to share a reference with a privately help object or array, and then mutate it.
So an unserializable class can maintain invariants -- that a privately held object does not escape -- that a serializable class cannot maintain.
Make it immutable by keeping all state information in a form where it can not be changed after the object is created.
Java does not allow perfect immutability in some cases.
Serializable is something that you can do but it isn't perfect because there has to be a way to recreate an exact copy of an object when deserializing and it may not be sufficient to use the same constructors to deserialize and to create the object in the first place. That leaves a hole.
Some things to do:
Some other things to think about:
The simple answer is that in most cases, just follow the two rules at the top of this answer and that will be good enough to handle your needs for immutability.
As others have said, one could make the argument that serialization results in a brand new object, which is then immutable, so no, serialization doesn't break it, but I think there's a bigger picture to immutability we have to consider before answering that question.
I think the real answer depends completely on the class being serialized, and the level of immutability required, but since the interviewer failed to give us source code, I will come up with my own. I'd also like to point out that, as soon as people start talking about immutability, they start throwing around the
final
keyword - yes, that makes a reference immutable, but it's not the only way to achieve immutability. Okay, let's look at some code:Is this class mutable because I implemented
Serializable
? Is it mutable because I didn't use thefinal
keyword? No way - it's immutable in every practical sense of the word, because I'm not going to modify the source code (even if you ask me to nicely), but more importantly, it's immutable because no outside class can change the value ofvalue
, short of using Reflection to make it public and then modifying it. By that token, I suppose you could run some intermediary hex editor and manually modify the value in RAM too, but that doesn't make it any more mutable than it was before. Extending classes can't modify it either. Sure, you can extend it and then overridegetValue()
to return something different, but doing so will not have changed the underlyingvalue
.I know this might rub a lot of people the wrong way, but it's my opinion that immutability is often purely semantic - e.g. is it immutable to someone calling your code from an outside class, or is it immutable from someone using BusPirate on your motherboard? There are VERY good reasons to use
final
to help ensure immutability, but I think it's importance is vastly overstated in more than a few arguments. Just because the JVM is allowed to do some magic under the hood to ensure Serialization works doesn't mean the level of immutability your application requires is somehow broken.You can prevent from serialization or cloning with the help of SecurityManager in java
}