I'm working on a project that requires me to serialize and deserialize generic objects. The way I'm going about this, is defining an abstract class Serializer
that implements a toBytes()
and a static fromBytes()
. All is well with this approach, as I can pass an object instance to a generic class Foo
that expects a Serializer
subclass, and I can ensure the object knows how to serialize and deserialize itself.
Now my question. Java serialization kinda sucks. I have multiple implementations I'd like to try swapping in and out, and ultimately I'd like the user to be able to decide the format. How would I go about changing the implementation details of Serializer
? I know I can't override static methods, so how would I do this without decoupling Foo
and Serializer
and not being able to ensure my generic object has the appropriate toBytes()
and fromBytes()
method in Foo
?
Here is code if anyone is confused:
public abstract class Serializer {
public static Serializer fromBytes(byte[] bytes) {
...
}
public byte[] toBytes() {
...
}
}
public class Foo<T extends Serializer> {
private T t;
public Foo(T t) {
this.t = t;
}
public void foo() {
t.toBytes(); //this will polymorph into the correct call because it's called on the object instance and not the Serializer class
}
public void bar(byte[] bytes) {
T.fromBytes(bytes); // I'd like to be able to override this method so I can use different implementations
}
}
I'm not sure if this is a good approach, but how about using Jackson library and serialize your object as a json node? for example:
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY,
property = "type")
@JsonSubTypes({
@Type(value = SoundFile.class, name = "sound"),
@Type(value = VideoFile.class, name = "video")
})
abstract class File{
private String id;
private String type;
@JsonCreator
public File(@JsonProperty("id") String id)
{
this.id=id;
}
public String getId() {return this.id;}
public abstract String getType();
}
class SoundFile extends File{
@JsonCreator
public SoundFile(@JsonProperty("id") String id) {
super(id);
}
@Override
public String getType() {
return "sound";
}
}
class VideoFile extends File{
@JsonCreator
public VideoFile(@JsonProperty("id") String id) {
super(id);
}
@Override
public String getType() {
return "video";
}
}
public class GenericApp {
public static void main(String[] args) {
ObjectMapper om = new ObjectMapper();
List<File> files = Arrays.asList(new VideoFile("1"),new SoundFile("2"));
//serialize
List<byte[]> fileSerialized = files.stream().map(file->{
try {
return om.writeValueAsBytes(file);
}catch(Exception e) {return null;}
}).collect(Collectors.toList());
//de-serialize
List<File> filesDeSerialized = fileSerialized.stream().map(bytes ->{
try {
return om.readValue(bytes, File.class);
}
catch(Exception e) {return null;}
}).collect(Collectors.toList());
filesDeSerialized.stream().forEach(file->{
System.out.println("id :"+file.getId()+" - "+file.getClass());
});
}
}
this would properly deserialize these objects and print:
id :1 - class com.dsncode.stackoverflow.VideoFile
id :2 - class com.dsncode.stackoverflow.SoundFile
however, you should define a @JsonTypeInfo and a @JsonSubType for all your sub-classes of your Generic Type. Because, by indicating this field, you will indicate to Jackson deserializer, which class should create for your generic type.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.