I'm getting this error when I try to serialize a Method object.
java.io.NotSerializableException: java.lang.reflect.Method
Any Idea?
You can do it manually. Just serialize your class name, method name and parameter class names as strings and then recreate your Method object using a reflection mechanism during deserialization.
Class.forName(clsName).getMethod("methodName", Class.forName(param1ClsName), ....);
If you implement Externalizable interface then You can use your class as regular serializable class.
There is no way to serialize a method object in a portable way since it doesn't contain all the necessary information to restore it (for example, the bytecode).
Instead, you should serialize the name of the class, the method name and the parameter types. Then you can recreate the Method instance during deserialization.
java.lang.reflect.Method does not implement java.io.Serializable. So it can not be serialized using the build-in Java methods.
Assuming that the java.lang.reflect.Method object is a member of another class, you should mark it as transient, and recreate it using class name and method name/signature after deserialization.
You could implement an MethodInfo class for this purpose.
class SerializableClass {
private transient Method m_method; //Not serialized
private MethodInfo m_methodInfo;
public Method getMethod() {
if(m_method != null) {
//Initailize m_method, based on m_methodInfo
}
return m_method;
}
}
Related
My singleton class be like this:
public class SerializableSingleton implements Serializable {
private static SerializableSingleton instance = new SerializableSingleton();
private SerializableSingleton() {
System.out.println("Constructor is being called");
}
public static SerializableSingleton getInstance() {
return instance;
}
}
Now it's written on the web that when we deserialize this singleton object, it will give a new instance back and not the previous one, and in order to fix this, use the readResolve() method.
But my question is - How is it even possible? When a static class member can't be serialized, how does the question of deserializing it comes at all? and it is all over the net?
Since the singleton object is static:
private static SerializableSingleton instance = new SerializableSingleton();
How is an instance getting serialized in the first place?
Serialization bypasses a lot of things in the language and even does some stuff that is not even possible with ordinary reflection.
When an object is serialized, it's class name and all instance fields (that are not transient) are written to the stream.
The magic happens when deserializing an object.
First, a new instance of the class is allocated.
To do that, the no-argument constructor of the first non-serializable superclass is called. The constructor of the serializable class (and serializable superclasses) are skipped. How? Magic.
Then all instance fields of the serializable classes are set.
(This step can be customized using a private void readObject(ObjectInputStream) method)
Lastly, a readResolve() method is called - if such a method exists. It's result is used as the result of deserializing the object.
(This does not apply to records, instances of java.lang.Class, java.lang.String, java.lang.Enum...)
In your example, this means that a new instance of your SerializableSingleton is created - bypassing your private constructor and instead calling java.lang.Object.<init>() - so you won't see the "Constructor is being called" output.
Now you have two instances of an "Singleton". To restore the original singleton semantics (there only ever exists one single instance of that class), we replace the just-deserialized-instance with the canonical instance:
private Object readResolve() {
return getInstance();
}
tl;dr: Java's serialization is complicated and sometimes indistinguishable to black magic. Using java's serialization opens the door to some surprising behaviors.
As the docs say:
By implementing the readResolve method, a class can directly control
the types and instances of its own instances being deserialized. The
method is defined as follows:
ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
And:
... For example, a Symbol class could be created for which only a
single instance of each symbol binding existed within a virtual
machine. The readResolve method would be implemented to determine if
that symbol was already defined and substitute the preexisting
equivalent Symbol object to maintain the identity constraint. In this
way the uniqueness of Symbol objects can be maintained across
serialization.
And:
A writeObject method to control what information is saved ...
A readObject method [..] to read the information written ...
A writeReplace method to allow a class to nominate a replacement object to be written to the stream
A readResolve method to allow a class to designate a replacement object for the object just read from the stream
To get full control of Serialization (also to serialize static and transient fields) you have to implement the Externalization interface:
The writeExternal and readExternal methods of the Externalizable
interface are implemented by a class to give the class complete
control over the format and contents of the stream for an object and
its supertypes.
So writeReplace and readResolve methods give you some more control than the ordinary (and automated) serialization mechanism, that is, replace the object before/after serialization. and it is not urgently linked to Singleton serialization, but to fulfill the proxy pattern for serialization. But as you mentioned, this mechanism is also used to implement serialization of a Singleton.
I have:
class MyClass extends MyClass2 implements Serializable {
//...
}
In MyClass2 is a property that is not serializable. How can I serialize (and de-serialize) this object?
Correction: MyClass2 is, of course, not an interface but a class.
As someone else noted, chapter 11 of Josh Bloch's Effective Java is an indispensible resource on Java Serialization.
A couple points from that chapter pertinent to your question:
assuming you want to serialize the state of the non-serializable field in MyClass2, that field must be accessible to MyClass, either directly or through getters and setters. MyClass will have to implement custom serialization by providing readObject and writeObject methods.
the non-serializable field's Class must have an API to allow getting it's state (for writing to the object stream) and then instantiating a new instance with that state (when later reading from the object stream.)
per Item 74 of Effective Java, MyClass2 must have a no-arg constructor accessible to MyClass, otherwise it is impossible for MyClass to extend MyClass2 and implement Serializable.
I've written a quick example below illustrating this.
class MyClass extends MyClass2 implements Serializable{
public MyClass(int quantity) {
setNonSerializableProperty(new NonSerializableClass(quantity));
}
private void writeObject(java.io.ObjectOutputStream out)
throws IOException{
// note, here we don't need out.defaultWriteObject(); because
// MyClass has no other state to serialize
out.writeInt(super.getNonSerializableProperty().getQuantity());
}
private void readObject(java.io.ObjectInputStream in)
throws IOException {
// note, here we don't need in.defaultReadObject();
// because MyClass has no other state to deserialize
super.setNonSerializableProperty(new NonSerializableClass(in.readInt()));
}
}
/* this class must have no-arg constructor accessible to MyClass */
class MyClass2 {
/* this property must be gettable/settable by MyClass. It cannot be final, therefore. */
private NonSerializableClass nonSerializableProperty;
public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) {
this.nonSerializableProperty = nonSerializableProperty;
}
public NonSerializableClass getNonSerializableProperty() {
return nonSerializableProperty;
}
}
class NonSerializableClass{
private final int quantity;
public NonSerializableClass(int quantity){
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
}
MyClass2 is just an interface so techinicaly it has no properties, only methods. That being said if you have instance variables that are themselves not serializeable the only way I know of to get around it is to declare those fields transient.
ex:
private transient Foo foo;
When you declare a field transient it will be ignored during the serialization and deserialization process. Keep in mind that when you deserialize an object with a transient field that field's value will always be it's default (usually null.)
Note you can also override the readResolve() method of your class in order to initialize transient fields based on other system state.
If possible, the non-serialiable parts can be set as transient
private transient SomeClass myClz;
Otherwise you can use Kryo. Kryo is a fast and efficient object graph serialization framework for Java (e.g. JAVA serialization of java.awt.Color requires 170 bytes, Kryo only 4 bytes), which can serialize also non serializable objects. Kryo can also perform automatic deep and shallow copying/cloning. This is direct copying from object to object, not object->bytes->object.
Here is an example how to use kryo
Kryo kryo = new Kryo();
// #### Store to disk...
Output output = new Output(new FileOutputStream("file.bin"));
SomeClass someObject = ...
kryo.writeObject(output, someObject);
output.close();
// ### Restore from disk...
Input input = new Input(new FileInputStream("file.bin"));
SomeClass someObject = kryo.readObject(input, SomeClass.class);
input.close();
Serialized objects can be also compressed by registering exact serializer:
kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));
If you can modify MyClass2, the easiest way to address this is declare the property transient.
Depends why that member of MyClass2 isn't serializable.
If there's some good reason why MyClass2 can't be represented in a serialized form, then chances are good the same reason applies to MyClass, since it's a subclass.
It may be possible to write a custom serialized form for MyClass by implementing readObject and writeObject, in such a way that the state of the MyClass2 instance data in MyClass can be suitably recreated from the serialized data. This would be the way to go if MyClass2's API is fixed and you can't add Serializable.
But first you should figure out why MyClass2 isn't serializable, and maybe change it.
You will need to implement writeObject() and readObject() and do manual serialization/deserialization of those fields. See the javadoc page for java.io.Serializable for details. Josh Bloch's Effective Java also has some good chapters on implementing robust and secure serialization.
You can start by looking into the transient keyword, which marks fields as not part of the persistent state of an object.
Several possibilities poped out and i resume them here:
Implement writeObject() and readObject() as sk suggested
declare the property transient and it won't be serialized as first stated by hank
use XStream as stated by boris-terzic
use a Serial Proxy as stated by tom-hawtin-tackline
XStream is a great library for doing fast Java to XML serialization for any object no matter if it is Serializable or not. Even if the XML target format doesn't suit you, you can use the source code to learn how to do it.
A useful approach for serialising instances of non-serializable classes (or at least subclasses of) is known a Serial Proxy. Essentially you implement writeReplace to return an instance of a completely different serializable class which implements readResolve to return a copy of the original object. I wrote an example of serialising java.awt.BasicStroke on Usenet
This hasn't been covered in my course and I am having trouble thinking up a reason why would I want this. I've come across the code below:
OpenNetworking proxy = service.getPort(OpenNetworking.class);
In the above line I can see that it is returning the port and it is passing the class to the method but I read this as the OpenNetworking.class isn't instantiated yet. I'm obviously missing something.
This is an example of a Factory method pattern.
The class type is provided to the service to give a Port on the specified type OpenNetworking.
A class type, in this case, is handy as it is a simplest way to provide a unique identifier to an object when doing object creation. It doesn't need to be maintained, should the state of the object changes as the class contains the type of the object.
There can be many reasons to do that:
Controlling number of instances of a class: Say you want to control how many instances you want for a class, you can make constructor
private or package level and return same instance when somebody calls
your method
Security: You might want your class to be secure and generally don't want to allow anybody to instantiate your class.
Dependency: Your class might have dependency which can be figured out only at runtime and then service class use reflection to
instantiate class appropriately.
Here we are passing the class type (Class in Java). So the treatment in the method getPort is done based on the Type of Class, we don't need an Object instance to handle it.
It is different, of course, than this code (whic doesn't compile):
OpenNetworking proxy = service.getPort(new OpenNetworking());
Also because of limitations of generics, when you have a generic class/method and you need to create a new instance, you will need a class. For example:
class SomeClass<T> {
public static<T> T create() {
return new T(); // will not work
}
public static<T> T create(Class<T> clazz) {
return clazz.newInstance(); //will work
}
}
so you need class instance to create a new object of that type.
Apparently the method service.getPort(); behaves according to the type in the parameter, imagin that there is a port for openNetworking and another one for closeNetworking, so providing the class name as a parameter would be enough to get the needed port number, one can create an enumeration for that but then extending existing code would force you to extend your enumeration too for each type.
The used method has this definition:
public <T> T getPort(Class<T> serviceEndpointInterface)
So it returns an instance of an object which extends the class T (a proxy,synthetic class instance)
I'm getting the java.io.NotSerializableException.
How can I serialize an object that does not implement java.io.Serializable?
I would like to serialize it in a stream.
I want to serialize an object from an external API. I can't modify this API.
In the external API, this object does not implement java.io.Serializable
Sure there are private fields, but there are a lot of getter and setter methods.
There are public static fields, and there is not a no-arg constructor, really, there is no constructor.
I think it's difficult to serialize it, isn't it?
Any suggestion?
if you can override the external API can create your own class which is a child of the external class.
Your child class can implement Serializable interface and you can serialize your class.
For ex-
ur external class is
class ExternalAPIClass
{
..
..
}
Class MyClass extends ExternalAPIClass implements Serializable
{
....
...
...
}
From what I understand from your question, you can create new instances of that object, and set their fields through setters. Then I suggest you use the getters to extract all the fields of the object into a Map, and then serialize that map.
Later you deserialize the map, create a new instance of the object, and set all the fields back with the setters.
Of course this is assuming there isn't any read only field that is set at construction time, like an ID. Because in that case the ids would be different.
How can I serialize an object that does not implement Serializable? I cannot mark it Serializable because the class is from a 3rd party library.
You can't serialise a class that doesn't implement Serializable, but you can wrap it in a class that does. To do this, you should implement readObject and writeObject on your wrapper class so you can serialise its objects in a custom way.
First, make your non-serialisable field transient.
In writeObject, first call defaultWriteObject on the stream to store all the non-transient fields, then call other methods to serialise the individual properties of your non-serialisable object.
In readObject, first call defaultReadObject on the stream to read back all the non-transient fields, then call other methods (corresponding to the ones you added to writeObject) to deserialise your non-serialisable object.
I hope this makes sense. :-)
Wrap the non-serializable class in a class of your own that implements Serializable. In your class's writeObject method, do whatever's necessary to serialize sufficient information on the non-serializable object so that your class's readObject method can reconstruct it.
Alternatively, contact the developer of the non-serializable class and tell him to fix it. :-)
You can use Kryo. It works on non serialized classes but classes needs registered aforehand.
If your class already implements the Serializable interface (required for serializing), all you must do is to declare the field you don't want to serialize with transient:
public transient String description;
If the class is not final, you can make your own class that extends it and implements Serializable. There are lots of other ways to serialize besides Java's built-in mechanism though.