I would like to serialize a Java class on my MySQL database using Ebean ORM.
My class definition is similar to the following:
public class Test implements Serializable
{
#Id
private Long id;
...
...
...
#Lob
private MyClass1 obj1;
#Lob
private MyClass2 obj2;
...
...
//getters and setters
}
where my classes MyClass1 and MyClass2 are basically wrappers for a
float[]
and an
Hashmap<String, Float>
and both implement Serializable interface.
I don't want to have to create a class with:
#Lob
byte[] obj1bytes;
#Transient
MyClass1 obj1Obj;
#Lob
byte[] obj2bytes;
#Transient
MyClass2 obj2Obj;
//getters and setters
What I would like to obtain is serialize and deserialize this class automatically WITHOUT having to use byte[] arrays to hold obj1 and obj2 in my Test class to a MySQL table in two LongBlob fields using
Ebean.save(testClassInstance);
Ebean.find(Test.class, ID);
EDIT1: MyClass1 is defined as following:
public class MyClass1 implements Interface1 {
private float[] vector;
public MyClass1 () {
}
public MyClass1 (float[] vector) {
this.vector = vector;
}
public float[] getVector() {
return vector;
}
public void setVector(float[] vector) {
this.vector = vector;
}
#Override
public byte[] serialize() throws Exception {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(object);
out.close();
return byteOut.toByteArray();
}
#Override
public void deserialize(byte[] bytes) throws Exception {
ByteArrayInputStream byteInt = new ByteArrayInputStream(bytes);
ObjectInputStream out = new ObjectInputStream(byteInt);
vector = (float[])out.readObject();
}
#Override
public float cossim(MyClass1 v) throws Exception {
method logic
}
#Override
public MyClass1 add(MyClass1 v) throws Exception {
method logic
}
}
MyClass2 is defined as MyClass1, only that instead of float[] vector I have a HashMap < String, Float > (). The only differences worth noting are serialize() and deserialize():
#Override
public byte[] serialize() throws Exception {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
DataOutputStream out = new DataOutputStream(outStream);
out.writeInt(map.size());
Iterator<String> iterator = map.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
out.writeUTF(key);
out.writeFloat(map.get(key));
}
return outStream.toByteArray();
}
#Override
public void deserialize(byte[] bytes) throws Exception {
try {
ByteArrayInputStream inStream = new ByteArrayInputStream(bytes);
DataInputStream in = new DataInputStream(inStream);
this.map = new HashMap<>();
int n = in.readInt();
for (int i = 0; i < n; i++) {
map.put(in.readUTF(), in.readFloat());
}
} catch (Exception ex) {
throw ex;
}
}
Actually it is not necessary to wrap float[] and HashMap<String,float> as they themselves are serializable.
Another thing is that if MyClass1 and MyClass2 are serializable than you can use #Lob. According to this wikibook,
By default in JPA any Serializable attribute that is not a
relationship or a basic type (String, Number, temporal, primitive),
will be serialized to a BLOB field.
In that wikibook, there is also an example using #Lob for the class Image.
#Entity
public class Employee {
...
#Basic(fetch=FetchType.LAZY)
#Lob
private Image picture;
...
}
Hope this might help you.
I did some coding after your reply.
Condition: The fields of ClassB should be serializable and the fields of fields should be serializable and ....
ClassB:
import java.io.Serializable;
public class ClassB implements Serializable{
private static final long serialVersionUID = 1L;
String b;
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
}
ClassA:
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Lob;
#Entity
public class ClassA implements Serializable{
private static final long serialVersionUID = 1L;
#Id
String a;
#Lob
ClassB b;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public ClassB getB() {
return b;
}
public void setB(ClassB b) {
this.b = b;
}
}
Here, ClassA contains ClassB object. You can add any logic in ClassB and it works. I have small problem with your overriding of serialize and deserialize. I think you do not need to do that. It will be done by default as it is serialized. And at last, these codes do work as I have tried it.
Hope this will help you.
Related
public interface A extends C {
String getCh();
String getId();
String getReview();
}
public interface B extends C {
String getCh();
String getId();
String getReview();
}
#Data
#Builder
public class AImpl implements A{
private String ch;
private String id;
private String review;
}
#Data
#Builder
public class BImpl implements B{
private String ch;
private String id;
private String review;
}
so now to use the builders of these I do:
return AImpl.builder()
.ch("ch")
.id("id")
.review("somerview");
For B I do:
return BImpl.builder()
.ch("ch1")
.id("id1")
.review("some new review");
Is there a way where I can make this builder part into a function? I dont like the idea of repeating the same code again. Like where I can pass id channel and review in a function and I can the object?
Disclaimer: I have never really dealt with builders so there might be a really much better option :D
This approach writes builders for each interface individually.
This does require that the interfaces provide a setter method.
Using generics, the methods of the RootBuilder and BaseABuilder return an instance of the ImplABuilder so that the chain can continue properly.
This is a very simple implementation of the Thistype generic which in other languages exists by default. This implementation also relies on casting to the actual Thistype but if you set the generics properly, that shouldnt be an issue.
public class Test
{
public static void main(String[] args)
{
ImplA implA = ImplA
.builder()
.id("id")
.description("description")
.valueA("a")
.build();
}
}
public interface Root
{
String getId();
void setId(String id);
String getDescription();
void setDescription(String description);
}
public class RootBuilder<Thistype extends RootBuilder<Thistype, Instance>, Instance extends Root>
{
protected final Instance object;
RootBuilder(Instance object)
{
this.object = object;
}
public Thistype id(String value)
{
object.setId(value);
return (Thistype)this;
}
public Thistype description(String value)
{
object.setDescription(value);
return (Thistype)this;
}
public Instance build()
{
return object;
}
}
public interface BaseA extends Root
{
String getValueA();
void setValueA(String valueA);
}
public class BaseABuilder<Thistype extends BaseABuilder<Thistype, Instance>, Instance extends BaseA> extends RootBuilder<Thistype, Instance>
{
protected Instance object;
BaseABuilder(Instance object)
{
super(object);
}
public Thistype valueA(String value)
{
object.setValueA(value);
return (Thistype)this;
}
}
public interface BaseB extends Root
{
String getValueB();
void setValueB(String valueB);
}
public interface BaseC extends Root
{
String getValueC();
void setValueC(String valueC);
}
public final class ImplA implements BaseA
{
private String id;
private String description;
private String valueA;
private ImplA() { }
public static ImplABuilder builder()
{
return new ImplABuilder(new ImplA());
}
private static class ImplABuilder extends BaseABuilder<ImplABuilder, ImplA> // assuming ImplA is final
{
ImplABuilder(ImplA object)
{
super(object);
}
// additional methods for ImplA class
}
}
Honestly, I'm not sure the title fits this correctly; But I will try to explain my problem with examples.
Say I have two classes
public class Entity {
private static int lastID = 0;
private int ID;
private Entity(){};
public static Entity create(){
lastID++;
Entity ent = new Entity();
ent.ID = lastID;
return ent;
}
}
public class Blob extends Entity {
private int x,y;
pubic void setPos(int X,int Y){;
x = X;
y = Y;
}
}
The way I'd like to interface with the Entity factory would be in the form of
Blob b = Entity.create<Blob>();
Or something in that nature.
My best attempt was
public static <E extends Entity> E create(){
E ent = new E();
...
but that doesn't want to work.
I am afraid it can't be done without actually passing a class or its name as an argument.
You can then use a generic construction <E extends Entity<E>> to make it typesafe and avoid manual type casting.
public class Entity<E extends Entity<E>> {
private static int lastID = 0;
protected int ID;
protected Entity() {
}
public static <E extends Entity<E>> E create(Class<E> clazz) {
lastID++;
E newItem;
try {
newItem = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new RuntimeException(e); // let's hope your child classes will have a working default constructor
}
newItem.ID = lastID;
return newItem;
}
public int getID() {
return ID;
}
}
public class Blob extends Entity<Blob> {
private int x,y;
public Blob() {
}
public void setPos(int X,int Y){;
x = X;
y = Y;
}
}
public class AnotherBlob extends Entity<AnotherBlob> {
String help = "Help!";
public String help() {
return help;
}
}
// TEST!
public class Test {
public static void main(String[] args) {
Blob blob = Entity.create(Blob.class);
AnotherBlob anotherBlob = Entity.create(AnotherBlob.class);
System.out.println("Blob: " + blob.getClass() + " ID = " + blob.getID() +
"\nAnother blob: " + anotherBlob.getClass() + " ID = " + anotherBlob.getID());
}
}
A simple factory method might look something like this. Keep it in its own class (not in Entity class) and have the name Factory someplace in name so it has context
public static final Entity getInstance(String id){
Entity instance = null;
if(id.equals("Blob")) {
instance = new Blob();
}
else if(id.equals("Another Blob")) {
instance = new AnotherBlob();
}
// more Entity types here
return instance;
}
I create class with methods like a How to serialize an object into a string
and it every say error "java.lang.ClassCastException: java.lang.String cannot be cast to Myclass"
My codes:
1)
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import javax.xml.bind.DatatypeConverter;
public class Serialization {
public static Object fromString(String s) throws IOException,
ClassNotFoundException {
byte[] data = DatatypeConverter.parseBase64Binary(s);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(
data));
Object o = ois.readObject();
ois.close();
return o;
}
public static String toString(Serializable o) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(o);
oos.close();
return DatatypeConverter.printBase64Binary(baos.toByteArray());
}
}
2) - calling
MyClass hl = (MyClass) Serialization.fromString(items
.getString("data"));
hl.load(); // this is my method from class
3) MyClass - Hologram
public class Hologram implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private Location loc;
private String name;
private String displayname;
public ArmorStand stand;
public Hologram(String name, String displayname, Location loc) {
this.loc = loc;
this.name = name;
this.displayname = displayname;
ArmorStand as = (ArmorStand) loc.getWorld().spawnEntity(loc,
EntityType.ARMOR_STAND);
as.setGravity(false);
as.setCanPickupItems(false);
as.setCustomName(displayname);
as.setCustomNameVisible(true);
as.setVisible(false);
this.stand = as;
HologramManager.holograms.put(name, this);
}
public void move(Location loc) {
this.loc = loc;
stand.teleport(loc);
}
public Location getLocation() {
return this.loc;
}
public void remove() {
stand.remove();
HologramManager.holograms.remove(name);
}
public void removeHologram() {
HologramManager.remove(name);
}
public void changeName(String name) {
HologramManager.holograms.remove(this.name);
this.name = name;
HologramManager.holograms.put(name, this);
}
public void changeDisplayName(String displayName) {
this.displayname = displayName;
stand.setCustomName(displayname);
stand.setCustomNameVisible(true);
}
public void load() {
//todo
}
}
Based on the linked answer, the problem most likely lies in the code you aren't showing us. When you serialize your MyClass object, you are probably doing something like this:
MyClass hl;
String base64String = Serialization.toString(hl.toString());
However you should be calling it like this:
MyClass hl;
String base64String = Serialization.toString(hl);
If you pass a String to the serialization function, you'll get a String back when you call Serialization.fromString(). You want to get an object back that you can cast to a MyClass instance, so pass one of those into Serialization.toString().
The fromString() method in Serilization returns an Object, which you wouldnt be able to cast to the class MyClass. The below line is causing the classCastException
MyClass hl = (MyClass) Serialization.fromString(items
.getString("data"));
Let say I'm trying to remove a object which is stored in hashmap of ClassA. ClassB is a static class which has a destroy method to remove required object from hashmap. Even after removing it, later when I tried to remove another object, i see old element which was removed before still exist. Is there something I'm missing?
#Named
#Scope
public class ClassA implements Serializable
{
/**
*
*/
private static final long serialVersionUID = 1L;
private Map<String, ModelObject> modelObjects = new HashMap<String, ModelObject>();
public synchronized void addMo(ModelObject modelObject) {
modelObjects.put(modelObject.getUuid(), modelObject);
}
public synchronized ModelObject updateMo(ModelObject modelObject) {
return modelObjects.put(modelObject.getUuid(), modelObject);
}
public synchronized void removeMo(ModelObject modelObject) {
modelObjects.remove(modelObject.getUuid());
}
public synchronized void removeMo(String modelObjectId) {
modelObjects.remove(modelObjectId);
}
public ModelObject getMo(String uuid) {
return modelObjects.get(uuid);
}
}
ClassB is
public class ClassB{
private static ClassA manager;
#Autowired(required = true)
public void setmanager(ClassA manager) {
ClassB.manager = manager;
}
public static synchronized void destoryMo(String modelObjectID) {
// get ClassA bean
if (manager == null) {
LOG.error("Managed bean ClassA not found (null) ==> no modelObject update!");
}
ModelObject wb = manager.getMo(modelObjectID);
if(wb != null){
wb.removeAllCache();
wb = null;
manager.removeMo(modelObjectID);
}
LOG.info("Destroyed ModelObject with modelObject id :" + modelObjectID);
}
}
In java serialization class Mp3player extends ElectronicDevice implements Serializable in this code super class electronicdevice is not implemented serializable. here super class is also getting serialized. my understanding is super class is also gets serialized due to extends.let me know my understanding is correct or not.
import java.io.*;
class ElectronicDevice {
ElectronicDevice()
{
System.out.print("ed ");
}
}
class Mp3player extends ElectronicDevice implements Serializable {
Mp3player()
{
System.out.print("mp ");
}
}
class MiniPlayer extends Mp3player {
MiniPlayer()
{
System.out.print("mini ");
}
public static void main(String[] args) {
MiniPlayer m = new MiniPlayer();
try {
FileOutputStream fos = new FileOutputStream("dev.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(m); os.close();
FileInputStream fis = new FileInputStream("dev.txt");
ObjectInputStream is = new ObjectInputStream(fis);
MiniPlayer m2 = (MiniPlayer) is.readObject();
is.close();
System.out.println();
} catch (Exception x) {
System.out.print("x ");
}
}
}
No.During the process of serialization only the fields of Serializable objects are written out and restored.
According to javadocs
During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class.
Where as the fields of serializable subclasses will be restored from the stream.
Please look into this example
Here ElectronicDevice is not Serializable,where as Mp3player is Serializable.Observe the fields of respected classes behaviour in serialization process.
import java.io.*;
class ElectronicDevice {
public int i = 0;
protected ElectronicDevice()
{
System.out.println("ed ");
}
}
class Mp3player extends ElectronicDevice implements Serializable {
int j =0;
Mp3player()
{
System.out.println("mp ");
}
}
class MiniPlayer extends Mp3player {
MiniPlayer()
{
System.out.println("mini ");
}
public static void main(String[] args) {
MiniPlayer m = new MiniPlayer();
m.i = 30;
m.j = 40;
try {
System.out.println("i value before serialization: "+m.i);//prints 30
System.out.println("i value before serialization: "+m.j);//prints 40
FileOutputStream fos = new FileOutputStream("dev.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(m); os.close();
FileInputStream fis = new FileInputStream("dev.txt");
ObjectInputStream is = new ObjectInputStream(fis);
MiniPlayer m2 = (MiniPlayer) is.readObject();
is.close();
System.out.println("i value after serialization: "+m2.i);//prints o
System.out.println("j value after serialization: "+m2.j);//prints 40
System.out.println();
} catch (Exception x) {
x.printStackTrace();
System.out.print("x ");
}
}
}
Since super class doesn't implement Serializable contents of the super class wont get serialized. Only the contents of the subclass would get serialized. When you deserialize the default constructor of the superclass would get executed and the fields of the superclass initialized as if you invoked the default constructor.
Following example illustrates this.
public class SerializationTest {
public static class Base {
private String name;
public Base() {
this.name = "johnDow";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class Sub extends Base implements Serializable {
private static final long serialVersionUID = 1L;
private String age;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
public static void main(String[] args) throws Exception {
ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteArrayOS);
Sub s = new Sub();
s.setName("name");
s.setAge("10");
out.writeObject(s);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(byteArrayOS.toByteArray()));
Sub d = (Sub) ois.readObject();
System.out.println(d.getName() + "-" + d.getAge());
}
}
What gets printed is
johnDow-10
This is the rule for superclass serialization:
If you are a serializable class, but your superclass is NOT
serializable, then any instance variables you INHERIT from that
superclass will be reset to the values they were given during the
original construction of the object. This is because the
nonserializable class constructor WILL run.
Therefore, if you add some instance variables to ElectronicDevice, be aware that the superclass 's state will be not serialized. (unless the superclass implements Serializable)
my understanding is super class is also gets serialized due to
extends.let me know my understanding is correct or not.
The short answer is NO.
In java, every class is a subclass of Object. Does Object itself implement Serializable?
To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields”
Reference -
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html