I have a view object that needs to be serialized to store in a database, and then retrieved later
public class MachineView extends View implements Serializable {
String name;
int age;
public MachineView(String name, int age, Context context) {
super(context);
this.name = name;
this.age = age;
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int x = getWidth();
int y = getHeight();
int radius;
radius = 50;
Paint paint = new Paint();
//paint.setStyle(Paint.Style.FILL);
paint.setTextSize(x / 2);
...
}
}
The only problem is that the methods I am using to serialize objects only work for simple objects( i.e. objects that can be condensed to key value pairs )
below are serialize and read object methods:
//Serialize object
public static byte[] getSerializedObject(Serializable s) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(baos);
oos.writeObject(s);
} catch (IOException e) {
return null;
} finally {
try {
oos.close();
} catch (IOException e) {}
}
byte[] result = baos.toByteArray();
return result;
}
//read object
public static Object readSerializedObject(byte[] in) {
Object result = null;
ByteArrayInputStream bais = new ByteArrayInputStream(in);
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bais);
result = ois.readObject();
} catch (Exception e) {
result = null;
} finally {
try {
ois.close();
} catch (Throwable e) {
}
}
return result;
}
It seems that i can convert the object into a byte array, but every time i read the object back it returns null
your code works fine for me:
import java.io.*;
class Foo implements Serializable {
#Override public String toString() {
return "Foo [x="+x+"]";
}
int x;
}
class Bar implements Serializable {
#Override public String toString() {
return "Bar [foo="+foo+"]";
}
Foo foo;
}
public class Soxx {
public static byte[] getSerializedObject(Serializable s) {
ByteArrayOutputStream baos=new ByteArrayOutputStream();
ObjectOutputStream oos=null;
try {
oos=new ObjectOutputStream(baos);
oos.writeObject(s);
} catch(IOException e) {
return null;
} finally {
try {
oos.close();
} catch(IOException e) {}
}
byte[] result=baos.toByteArray();
return result;
}
//read object
public static Object readSerializedObject(byte[] in) {
Object result=null;
ByteArrayInputStream bais=new ByteArrayInputStream(in);
ObjectInputStream ois=null;
try {
ois=new ObjectInputStream(bais);
result=ois.readObject();
} catch(Exception e) {
result=null;
} finally {
try {
ois.close();
} catch(Throwable e) {}
}
return result;
}
public static void main(String[] args) {
Foo foo=new Foo();
foo.x=42;
Bar bar=new Bar();
bar.foo=foo;
byte[] bytes=getSerializedObject(bar);
Object object=readSerializedObject(bytes);
System.out.println(object);
}
}
outputs: Bar [foo=Foo [x=42]]
Related
Since Entity store is throwing out when storing null value, I managed to get a "hack" to save a null value into it. However I am not sure if my approach is futile.
Here's a snippet:
entityStore.executeInTransaction(new StoreTransactionalExecutable() {
#Override
public void execute(#NotNull final StoreTransaction txn) {
try {
entityStore.registerCustomPropertyType(txn, UndefinedIterable.class, UndefinedBinding.BINDING);
} catch (Exception e) {
}
final Entity entity = txn.newEntity(storeName);
Iterator<String> it = comparableMap.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
Comparable value = comparableMap.get(key);
if(value == null) {
entity.setProperty(key, new UndefinedIterable());
} else {
entity.setProperty(key, value);
}
}
First question here is, is it safe to registerCustomPropertyType over and over again, since this method will be called each time the server gets a POST request.
Next is the UndefinedIterable even needed here?
Here's the complete code
UndefinedIterable.java
public class UndefinedIterable implements Serializable, ByteIterable {
private byte[] bytes;
public UndefinedIterable() {
bytes = "null".getBytes();
}
#Override
public ByteIterator iterator() {
return new ArrayByteIterable(bytes).iterator();
}
#Override
public byte[] getBytesUnsafe() {
return bytes;
}
#Override
public int getLength() {
return bytes.length;
}
#NotNull
#Override
public ByteIterable subIterable(int offset, int length) {
return null;
}
#Override
public int compareTo(#NotNull ByteIterable o) {
return 0;
}
}
UndefinedBinding.java
public class UndefinedBinding extends ComparableBinding {
public static final UndefinedBinding BINDING = new UndefinedBinding();
#Override
public Comparable readObject(#NotNull ByteArrayInputStream stream) {
try {
byte[] serialized = ByteStreams.toByteArray(stream);
Comparable deserialized = deserialize(serialized, Comparable.class);
return deserialized;
} catch (Exception e) {
}
return null;
}
#Override
public void writeObject(#NotNull LightOutputStream output, #NotNull Comparable object) {
byte[] serialized = serialize(object);
output.write(serialized);
}
public static byte[] serialize(Object obj) {
try {
try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = new ObjectOutputStream(bos)) {
out.writeObject(obj);
return bos.toByteArray();
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static <T> T deserialize(byte[] data, Class<T> clazz) {
try {
ByteArrayInputStream in = new ByteArrayInputStream(data);
ObjectInputStream is = new ObjectInputStream(in);
return (T) is.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
I am afraid that my approach might be a bit overkill for the simple job of saving a null value?
It's safe to registerCustomPropertyType several times, though it is intended to be called usually once on an init stage.
If I really need to distinguish lack of property value and property having null value, then I'd try to define non-null values replacing null. For String, it can be hex representation of an UUID. For Integer, Integer.MIN_VALUE or Integer.MAX_VALUE, etc. Don't use values of mixed types for a single property, otherwise search by property value or range search won't work.
I would like to write serializer for Ehcache of Optional class. I know, that optional member is seriazizable, so I write:
#Override
public ByteBuffer serialize(Optional object) throws SerializerException {
if( object.isPresent() ) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
return ByteBuffer.wrap(baos.toByteArray()); // excess copying
} catch (IOException e) {
throw new AssertionError(e);
}
}
else {
return ByteBuffer.wrap(new byte[] {});
}
}
#Override
public Optional read(ByteBuffer binary) throws ClassNotFoundException, SerializerException {
if( binary.array().length > 0 ) {
try {
byte[] buf = binary.array();
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
ObjectInputStream ois = new ObjectInputStream(bais);
Object object = ois.readObject();
return Optional.of(object);
} catch (IOException e) {
throw new AssertionError(e);
}
}
else {
return Optional.empty();
}
}
I confused by commented line, which includes excess copying of data. Can I avoid it and serialize directly with ByteBuffer?
While does Ehcache seriazliers based of ByteBuffer?
ByteBuffer.wrap() doesn't actually copy data. As the name implies it wraps the array, so any changes to the original array would also be reflected in the buffer.
Sadly, you can't do Java serialization on a ByteBuffer. You are doing the same thing as the built-in PlainJavaSerializer of Ehcache.
By the way, you could remove a lot of code by doing this:
public class OptionalSerializer<T> implements Serializer<Optional<T>> {
private final PlainJavaSerializer<T> serializer;
public OptionalSerializer(ClassLoader classLoader) {
serializer = new PlainJavaSerializer<>(classLoader);
}
#Override
public ByteBuffer serialize(Optional<T> object) throws SerializerException {
return object.map(serializer::serialize).orElse(ByteBuffer.allocate(0));
}
#Override
public Optional<T> read (ByteBuffer binary) throws ClassNotFoundException, SerializerException {
if(binary.array().length > 0) {
return Optional.of(serializer.read(binary));
}
return Optional.empty();
}
#Override
public boolean equals(Optional<T> object, ByteBuffer binary) throws ClassNotFoundException, SerializerException {
return object.equals(read(binary));
}
}
On my serialized XML File is only one attribute of my Object saved, although four should be saved. I think this is due to y XStream Object registering only one converter, although he should register four.
My Converters are all functioning individually. I tested them one by one.
My XML File:
<object-stream>
<model.Product>13</model.Product>
</object-stream>
My Product class which should be saved:
public class Product implements Externalizable, Serializable {
private static final long serialVersionUID = -8437751114305532162L;
#XStreamConverter(converter.NameConverter.class)
private SimpleStringProperty name;
#XStreamConverter(converter.PriceConverter.class)
private SimpleDoubleProperty price;
#XStreamConverter(converter.CountConverter.class)
private SimpleIntegerProperty quantity;
#XStreamConverter(converter.IDConverter.class)
private long id;
public Product(String name, int quantity, double price, long id)
{
this.name=new SimpleStringProperty(name);
this.quantity=new SimpleIntegerProperty(quantity);
this.price=new SimpleDoubleProperty(price);
this.id=id;
//Getter and Setter and implentation of Externalizable
My XStream class
XStream xstream;
ObjectInputStream ois;
ObjectOutputStream oos;
#Override
public void close() throws IOException {
if (oos != null) {
oos.close();
}
if (ois != null) {
ois.close();
}
}
#Override
public void writeObject(Product obj) throws IOException {
try {
oos.writeObject(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
public void open(InputStream input, OutputStream output) throws IOException {
xstream = createXStream(model.Product.class);
converter.ConverterManager con=new ConverterManager();
con.registerAllConverters(xstream);
if (input != null) {
if (input.available() > 0) {
ois = xstream.createObjectInputStream(input);
}
}
if (output != null) {
oos = xstream.createObjectOutputStream(output);
}
}
}
My ConverterManager:
import com.thoughtworks.xstream.XStream;
public class ConverterManager {
public void registerAllConverters(XStream xstream)
{
xstream.aliasAttribute("Product Price", "price");
xstream.registerConverter(new PriceConverter());
xstream.aliasAttribute("Product ID", "id");
xstream.registerConverter(new IDConverter());
xstream.aliasAttribute("Product Name", "name");
xstream.registerConverter(new NameConverter());
xstream.aliasAttribute("Product quantity", "quantity");
xstream.registerConverter(new CountConverter());
}
}
My writeObject, open and close methods are called from this method from another class:
private void saveModel() {
XStreamStrategy s=new XStreamStrategy();
try {
s.open(getFilePath());
} catch (IOException e) {
e.printStackTrace();
}
for(fpt.com.Product p: model)
{
try {
s.writeObject(p);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
I try to read data from file "sinhvien.dat" then push into array of Student.
My code:
private Student[] docFile() {
Student[] std = null;
FileInputStream f = null;
ObjectInputStream inStream = null;
try {
f = new FileInputStream("student.dat");
inStream = new ObjectInputStream(f);
std = (Student[]) inStream.readObject();// this line throw error
} catch (ClassNotFoundException e) {
System.out.println("Class not found");
} catch (IOException e) {
System.out.println("Error Read file");
} finally {
if (inStream != null) {
try {
inStream.close();
} catch (IOException ex) {
}
}
if (f != null) {
try {
f.close();
} catch (IOException ex) {
}
}
}
return std;
}
Class Student
public class Student implements Serializable { private String studName; Student(String name) { this.studName = name; } public Student() { } public String getStudName() { return studName; } public void setStudName(String studName) { this.studName = studName; } #Override public String toString() { return "Student Name :" + studName; } }
I don't know how to fix this error.
sorry for bad english :(
Exception in thread "Thread-3" java.lang.ClassCastException: btvn_l5.Student cannot be cast to [Lbtvn_l5.Student;
This means, that you cannot cast a single Student-obect into an array of Student-objects.
I think you serialize a Student and try to deserialize a Student[]. Th prefix [L indicates an array.
Take a look at you serializer.
There're some library classes that although implement Serializable, fail to serialize correctly. I can't fix them, but I can extend ObjectOutputStream and ObjectInputStream for some workaround.
I want my ObjectOutputStream to write additional data for each instance of class A and ObjectInputStream to read and apply that data after A is deserialized.
Currently I have a mid-workaround that requires explicit additional calls to writeObject() and readObject(). I'd prefer to manage without these calls.
Uncomment /* */ blocks to see how it works.
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import org.junit.Test;
import static org.junit.Assert.*;
public class CloneSerializableTest2 {
// library classes
public static class A implements Serializable {
public transient String s1;
}
public static class MyA extends A {
public String s2;
}
/*
private static class AHolder implements Serializable {
private static final Field s1Fld;
static {
try {
s1Fld = A.class.getDeclaredField("s1");
s1Fld.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private String s1;
private A a;
public AHolder(A m) {
this.a = m;
try {
s1 = (String)s1Fld.get(m);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
public void restoreA() {
try {
s1Fld.set(a, s1);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
}
*/
#SuppressWarnings("unchecked")
public static <T> T cloneSerializable(T o) {
try {
/*
final List<AHolder> accumSrc = new ArrayList<AHolder>();
*/
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout)
/*
{
{
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException
{
if (obj instanceof A) {
accumSrc.add(new AHolder((A)obj));
}
return super.replaceObject(obj);
}
}
*/
;
out.writeObject(o);
/*
out.writeObject(accumSrc);
*/
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object copy = in.readObject();
/*
List<AHolder> accumDst = (List<AHolder>)in.readObject();
for (AHolder r : accumDst) {
r.restoreA();
}
*/
in.close();
return (T)copy;
} catch (IOException e) {
throw new RuntimeException("Unexpected error", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected error", e);
}
}
#Test
public void testIt() throws Exception {
try {
MyA m1 = new MyA();
m1.s1 = "a";
m1.s2 = "b";
m1 = cloneSerializable(m1);
assertEquals("a", m1.s1);
assertEquals("b", m1.s2);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}
Answering to myself
import java.io.*;
import java.lang.reflect.Field;
import org.junit.Test;
import static org.junit.Assert.*;
public class CloneSerializableTest2 {
// library classes
public static class A implements Serializable {
public transient String s1;
}
public static class MyA extends A {
public String s2;
}
private static class AHolder implements Serializable, Externalizable {
private static final Field s1Fld;
static {
try {
s1Fld = A.class.getDeclaredField("s1");
s1Fld.setAccessible(true);
} catch (NoSuchFieldException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private String s1;
private A a;
#SuppressWarnings("unused")
public AHolder() {
}
public AHolder(A m) {
this.a = m;
try {
s1 = (String)s1Fld.get(m);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
}
private Object readResolve() {
try {
s1Fld.set(a, s1);
} catch (IllegalAccessException e) {
throw new RuntimeException("Unexpected error", e);
}
return a;
}
#Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(s1);
ObjectOutputStream out2 = ((ObjectOutputStream)out);
out2.writeUnshared(a);
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
s1 = (String)in.readObject();
a = (A)in.readObject();
}
}
#SuppressWarnings("unchecked")
public static <T> T cloneSerializable(T o) {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout)
{
{
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException
{
if (obj instanceof A) {
obj = new AHolder((A) obj);
} else if (obj instanceof AHolder) {
obj = ((AHolder)obj).a;
}
return super.replaceObject(obj);
}
};
out.writeObject(o);
out.close();
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object copy = in.readObject();
in.close();
return (T)copy;
} catch (IOException e) {
throw new RuntimeException("Unexpected error", e);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unexpected error", e);
}
}
#Test
public void testIt() throws Exception {
try {
MyA m1 = new MyA();
m1.s1 = "a";
m1.s2 = "b";
m1 = cloneSerializable(m1);
assertEquals("a", m1.s1);
assertEquals("b", m1.s2);
} catch (Exception e) {
e.printStackTrace();
throw e;
}
}
}