I have the following serializable class (implements serializable):
public class Test implements Serializable{
private String id;
private Map<String,Object> otherProperties;
}
However , it seems like this property is causing some problems with serialization :
How can I solve this problem ?
Also , is there any downside in not making this transient or serializable ? Will I be able to serialize this class fully ?
The Map interface does not extend the Serializable interface, which is why Sonar is warning you.
When serializing an instance of Test, you must choose whether or not you want otherProperties to be serialized.
If you don't want to serialize otherProperties, then the field should be marked as transient:
private transient Map<String, Object> otherProperties;
Otherwise, you can change the type of otherProperties to an implementation of Map that implements Serializable, such as HashMap.
If it's an option (for instance, if you are using Jackson to (de)serialize your class), remove the Serializable marker from your Test class. The serialization will still work and you will get rid of the warning in Sonar.
Add this 2 methods to your class:
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
Map value type should be specified to extends Serialzable:
public class Test<T extends Serializable> implements Serializable{
private String id;
private Map<String,T> otherProperties;
}
I was having a similar issue but in contrast to Nexussim Lements I've been using an interface that gets serialized but still SonarLint showed me a warning:
public class BasicCheck implements Serializable { ... }
public class Case implements Serializable {
private BasicCheck basicCheck; // Sonarlint throws warning here
...
}
Luckily I've found FAlfeao's solution to be working. All I had to do was to add these two methods to my Case-class:
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
}
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
}
Related
I have a class as follows in a .jar file (library file):
class A{
//someimplementation
}
I would like to make it to implements Serializable interface as follows:
class A implements Serializable {
//the same implementation as present in classA
}
I do not want to decompile the jar file, changing the class signature and then archiving it again after compilation.
Is there any way like writing hooks to achieve this? Kindly provide any pointers/suggestions.
My ultimate aim is to achieve implementing Serializable interface without modifying the jar file.
You can probably achieve this using Serialization Proxy Pattern (Effective Java 2nd edition Item 78)
A few links about the Pattern :
http://jtechies.blogspot.com/2012/07/item-78-consider-serialization-proxies.html
http://java.dzone.com/articles/serialization-proxy-pattern
Follow up: instance control in Java without enum
Make a new class that extends A and is Serializable. In order to avoid serialization errors, however, because A isn't serializable, you need to make a SerializationProxy that creates a new instance via constructor or factory method instead of the normal Java Serialization mechanism of explicitly setting the fields outside of any constructor.
public class MySerializableA extends A implements Serializable{
private final Foo foo;
private final Bar bar;
...
private Object writeReplace() {
return new SerializationProxy(this);
}
//this forces us to use the SerializationProxy
private void readObject(ObjectInputStream stream) throws InvalidObjectException {
throw new InvalidObjectException("Use Serialization Proxy instead.");
}
//this private inner class is what actually does our Serialization
private static class SerializationProxy implements Serializable {
private final Foo foo;
private final Bar bar;
...
public SerializationProxy(MySerializableA myA) {
this.foo = myA.getFoo();
this.bar = myA.getBar();
...//etc
}
private Object readResolve() {
return new MySerializableA(foo, bar,...);
}
}
}
The only downside is when you want to serialize an A, you will have to wrap it in a MyA. but when deserializing, the cast to A will work fine.
I want to serialize a POJO class which is not under my control, but want to avoid serializing any of the properties which are coming from the superclass, and not from the final class. Example:
public class MyGeneratedRecord extends org.jooq.impl.UpdatableRecordImpl<...>,
example.generated.tables.interfaces.IMyGenerated {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
...
}
You can guess from the example that that this class is generated by JOOQ, and inherits from a complex base class UpdatableRecordImpl which also has some bean property-like methods, which cause problems during the serialization. Also, I have several similar classes, so it would be good to avoid duplicating the same solution for all of my generated POJOs.
I have found the following possible solutions so far:
ignore the specific fields coming from superclass using mixin technique like this: How can I tell jackson to ignore a property for which I don't have control over the source code?
The problem with this is that if the base class changes (e.g., a new getAnything() method appears in it), it can break my implementation.
implement a custom serializer and handle the issue there. This seems a bit overkill to me.
as incidentally I have an interface which describes exactly the properties I want to serialize, maybe I can mixin a #JsonSerialize(as=IMyGenerated.class) annotation...? Can I use this for my purpose?
But, from pure design point of view, the best would be to be able to tell jackson that I want to serialize only the final class' properties, and ignore all the inherited ones. Is there a way to do that?
Thanks in advance.
You can register a custom Jackson annotation intropector which would ignore all the properties that come from the certain super type. Here is an example:
public class JacksonIgnoreInherited {
public static class Base {
public final String field1;
public Base(final String field1) {
this.field1 = field1;
}
}
public static class Bean extends Base {
public final String field2;
public Bean(final String field1, final String field2) {
super(field1);
this.field2 = field2;
}
}
private static class IgnoreInheritedIntrospector extends JacksonAnnotationIntrospector {
#Override
public boolean hasIgnoreMarker(final AnnotatedMember m) {
return m.getDeclaringClass() == Base.class || super.hasIgnoreMarker(m);
}
}
public static void main(String[] args) throws JsonProcessingException {
final ObjectMapper mapper = new ObjectMapper();
mapper.setAnnotationIntrospector(new IgnoreInheritedIntrospector());
final Bean bean = new Bean("a", "b");
System.out.println(mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(bean));
}
}
Output:
{
"field2" : "b"
}
You can override the superclass' methods which you'd like to prevent from being output and annotate them with #JsonIgnore. The override shifts the control of property creation to the subclass while enabling its ability to filter it from the output.
For instance:
public class SomeClass {
public void setField1(...);
public Integer getField1();
public void setField2(...);
public Integer getField2();
#Override
#JsonIgnore
public String superClassField1(...){
return super.superClassField1();
};
#Override
#JsonIgnore
public String superClassField2(...){
return super.superClassField2();
};
...
}
You can use this as well instead of unnecessary overrides
#JsonIgnoreProperties({ "aFieldFromSuperClass"})
public class Child extends Base {
private String id;
private String name;
private String category;
}
The good use of inheritance is that the child classes extend or add functionality. So the usual way is to serialize the data.
A workarround would be to use a Value Object (VO) or Data Transfer Object (DTO) with the fields you need to serialize. Steps:
Create a VO class with the fields that should be serialized.
Use BeanUtils.copyProperties(target VO, source data) to copy the properties
Serialize the VO instance.
Add the following annotation in your Base Class :
#JsonInclude(Include.NON_NULL)
I have class SuperYo extending class Persona, like this:
public class SuperYo extends Persona {
private NotSerializableObj obj1
private NotSerializableObj obj2
private NotSerializableObj obj3
}
public class Persona {
private SerializableObj sObj1
private SerializableObj sObj2
private SerializableObj sObj3
}
The thing is, that I add to a LinkedList an Instance of Persona from SuperYo:
LinkedList<Persona> list = new LinkedList<Persona>();
list.add((Persona) superYo);
It adds it as a SuperYo Object! With all the NonSerializableObjs on it... and thus, cant be sent from a Socket :(.
So, the question is... is there any way of "downcasting" an object to its father class, so its attributtes are non present?
Thanks!
Implement readObject and writeObject in SuperYo as below:
private void writeObject(ObjectOutputStream outStream) throws IOException {
//write attributes from PersonYo only
outStream.defaultWriteObject();
outStream.writeObject(sObj1);
outStream.writeObject(sObj2);
outStream.writeObject(sObj2);
}
private void readObject(ObjectInputStream inStream) throws IOException,
ClassNotFoundException {
//read attributes from PersonYo only
inStream.defaultReadObject();
sObj1= (SerializableObj)inStream.readObject();
sObj2= (SerializableObj)inStream.readObject();
sObj3= (SerializableObj)inStream.readObject();
}
Once you do this, there will be no need of down-casting. Also you may have better control on other non-serializable attributes in the object.
Casting is a matter of polymorphism. When you cast an object of type1 to type2, the instance won't change, but you just look at the instance from a new perspective!
If you want to send the child class over the network, you can make the SuperYo members as transient, and fill them on instantiation. Or you can add writeObject() and readObject() methods to your child class.
I have different kinds of serializable ObjectState's that store state data for important application objects. I do this so I can persist these important objects arcoss application instatances. The user will sometimes need to group certain objects together into containers, so some of the ObjectState's are placed into an array of ObjectState's and passed to a ContainerState (just a serializable class that holds an array of generic types serializables).
My question is, how do I de-serialize the ContianerState and keep type integrity? I thought I could try something like:
public static ContainerState<V> inflateState(V v, Serializable state) throws ClassCastException {
return (ContainerState<V>)state;
}
But that won't even get past Eclipses' warning system. I also tried V.class to the same result. Is it even possible for me to achieve this?
EDIT 1:
I tried this, it seems to work, but I'm not sure if it's the best way. Any thoughts?
public static <cls extends Serializable> ContainerState<cls> inflateState(Class<? extends Serializable> cls, Serializable state) throws ClassCastException {
return (ContainerState<cls>)state;
}
This should at least compile:
public static <C extends Serializable> ContainerState<C> inflateState(Class<C> cls, Serializable state) throws ClassCastException {
return (ContainerState<C>)state;
}
I have a class that is something like the following:
public class Foo {
static byte[] convertToArray(Foo f);
static Foo convertToFoo(byte[] ba);
}
How can I use convertToArray and convertToFoo to allow Foo to implement java.io.Serializable? The default serialization procedure doesn't seem like a good solution for my class because it would require changing a lot of other classes to implement Serializable. However, I already have a way to go to and from bytes, so there should be an easy way for Foo to implement serializable without having to declare all dependent members as Serializable. I suspect overriding readObject and writeObject is the way to go, but what is the correct way to do this, since these are instance methods with return type void?
Check out Externalizable, which is a subinterface of Serializable. Its readExternal and writeExternal methods delegate the serialization details to the programmer, which sounds appropriate in your case.
During deserialization (in your implementation of readExternal), you will need to use Foo.convertToFoo to convert the bytes from an ObjectInput to a Foo object, and then copy all of the state of that Foo object into this.
A snippet from the Javadoc that describes the semantics of Externalizable:
Only the identity of the class of an
Externalizable instance is written in
the serialization stream and it is the
responsibility of the class to save
and restore the contents of its
instances. 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. These
methods must explicitly coordinate
with the supertype to save its state.
These methods supersede customized
implementations of writeObject and
readObject methods.
Assuming your class is final then you probably want to use a serial proxy (see Effective Java). Implement Serializable, but make readObject, readObjectNoData and writeObject throw an exception. Use writeReplace to produce a serialisable proxy object containing the binary data. In the proxy, use readResolve to create a Foo from the data.
public final class Foo implements Serializable {
private static final long serialVersionUID = 42L;
private static final ObjectStreamField[] serialPersistentFields = { }
static byte[] convertToArray(Foo f) { ... }
static Foo convertToFoo(byte[] ba) { ... }
private void writeObject(
ObjectOutputStream out {
) throws IOException {
throw new NotSerializableException();
}
private void readObject(
ObjectInputStream in
) throws IOException, ClassNotFoundException {
throw new NotSerializableException();
}
private void readObjectNoData(
) throws ObjectStreamException {
throw new NotSerializableException();
}
private Object writeReplace() throws ObjectStreamException {
return new FooSerialProxy(this);
}
}
/* pp */ final class FooSerialProxy implements Serializable {
private static final long serialVersionUID = 42L;
private final byte[] data;
/* pp */ FooSerialProxy(Foo foo) {
this.data = Foo.convertToArray(foo);
}
private Object readResolve() throws ObjectStreamException {
return Foo.convertToFoo(data);
}
}