I'm writing a serializable class that takes several arguments, including a Function
:
public class Cls implements Serializable {
private final Collection<String> _coll;
private final Function<String, ?> _func;
public Cls(Collection<String> coll, Function<String, ?> func) {
_coll = coll;
_func = func;
}
}
func
is stored in a member variable, and so needs to be serializable. Java lambdas are serializable if the type they're being assigned to is serializable. What's the best way to ensure that the Function
I get passed in my constructor is serializable, if it is created using a lambda?
Create a SerializableFunction
type and use that:
public interface SerializableFunction<F, R> implements Function<F, R>, Serializable {}
....
public Cls(Collection<String> coll, SerializableFunction<String, ?> func) {...}
Issues:
coll
and func
arguments, in that func
is declared as serializable in the signature, but coll
is not, but both are required to be serializable for it to work.Function
that are serializable.Use a type parameter on the constructor:
public <F extends Function<String, ?> & Serializable>
Cls(Collection<String> coll, F func) {...}
Issues:
func
argument is required to implement Serializable
in the compile-time type heirarchy, but coll
is just required to be serializable somehow (although this requirement can be cast away if required).EDIT This code doesn't actually compile when trying to call with a lambda or method reference.
Leave it up to the caller
This requires the caller to know (from the javadocs, or trial-and-error) that the argument needs to be serializable, and cast as appropriate:
Cls c = new Cls(strList, (Function<String, ?> & Serializable)s -> ...);
or
Cls c = new Cls(strList, (Function<String, ?> & Serializable)Foo::processStr);
This is ugly IMO, and the initial naive implementation of using a lambda is guaranteed to break, rather than likely to work as with coll
(as most collections are serializable somehow). This also pushes an implementation detail of the class onto the caller.
At the moment I'm leaning towards option 2, as the one that imposes the least burden on the caller, but I don't think there's an ideal solution here. Any other suggestions for how to do this properly?
EDIT: Perhaps some background is required. This is a class that runs inside storm, in a bolt, which is serialized to transfer to a remove cluster to execute. The function is performing an operation on the processed tuples when run on the cluster. So it is very much part of the class's purpose that it is serializable and that the function argument is serializable. If it is not, then the class is not usable at all.
For serializing the object, we call the writeObject() method of ObjectOutputStream class, and for deserialization we call the readObject() method of ObjectInputStream class. We must have to implement the Serializable interface for serializing the object.
The interface must be implemented by any class which uses the interface for serializing its objects. By default, the classes such as wrapper classes and the String class implement the interface java. io. Serializable.
To exclude members from being serialized define them as transient . E.g. b will not be serialized in this class. Save this answer.
Serialization in Java is the concept of representing an object's state as a byte stream. The byte stream has all the information about the object. Usually used in Hibernate, JMS, JPA, and EJB, serialization in Java helps transport the code from one JVM to another and then de-serialize it there.
In most cases the answer is: don’t.
You may notice that most classes of the JRE, even ObjectOutputStream.writeObject
do not enforce Serializable
in their signature. There are simply too many APIs not specifically to Serialization where the compile-time information about an object implementing Serializable
gets lost and using them together with Serialization would require lots of type casting if the latter enforced their inputs to be Serializable
.
Since one of your parameters is a Collection
, you may get examples from that API:
Collections.unmodifiableList
:
The returned list will be serializable if the specified list is serializable.
You will find more of these operations which care to retain the Serialization capability without retaining the Serializable
compile-time type on the result.
This also applies to all non-public
types, e.g. the results of Collections.emptyList()
, Arrays.asList(…)
and Comparator.reverseOrder()
. They all are Serializable
without declaring it.
Further, every class having more use cases than just getting serialized should refrain from enforcing to be always Serializable
. That would hinder the uses where no Serialization is involved.
Regarding the Collection
parameter, you may consider removing the serializable constraint at all. Normally, you protect your class against later-on changes to the collection you received. A simple solution is to copy the collection and when your doing it, you may use a type which supports Serialization.
Even if you want to avoid copying, the Serialization itself is a copying process per se, so you can simply create custom readObject
and writeObject
methods storing the contents of the Collection
, eliminating the need to have a Serializable
collection.
To summarize it, usually the policy is that if the user of your class intends to serialize instances of it, it’s the responsibility of the user that all components put into it are themselves Serializable
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With