I have read a little bit about 3rd party serialization methods such as JSON, but was wondering if there is any other way to serialize objects such as an area that do not implement serializable. In other word would JSON be the best way to serialize such an object?
EDIT : Throwing A NotSerializable Exception
public class Test {
public static void main(String[] args) throws Exception {
Pojo pojo = new Pojo(new Area()); // The original object, NOT SERIALIZABLE !
byte[] pojoBytes = Serializer.serialize(pojo); // Serialize
pojo = (Pojo) Serializer.deserialize(pojoBytes); // Deserialize
System.out.println(pojo); // Good as new !
}
}
public class Pojo implements Serializable {
private final Area msg;
public Pojo(Area msg) {
this.msg = msg;
}
public Area getMsg() {
return msg;
}
public String toString() {
return "Pojo says : " + msg;
}
}
public class Serializer {
public static byte[] serialize(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
FileOutputStream fileOut = new FileOutputStream("Test.ser");
ObjectOutputStream oos = new SurrogateObjectOutputStream(fileOut); // Magically handle Pojos !
oos.writeObject(o);
oos.flush();
oos.close();
return baos.toByteArray();
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
FileInputStream fileIn = new FileInputStream("Test.ser");
ObjectInputStream ois = new ObjectInputStream(fileIn);
Object o = ois.readObject();
bais.close();
return o;
}
}
public class SurrogateObjectOutputStream extends ObjectOutputStream {
public SurrogateObjectOutputStream(OutputStream out) throws IOException {
super(out);
enableReplaceObject(true);
}
protected SurrogateObjectOutputStream() throws IOException, SecurityException {
super();
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException {
if (obj instanceof Pojo) {
return new PojoSurrogate((Pojo) obj);
} else return super.replaceObject(obj);
}
}
public class PojoSurrogate implements Serializable {
private Area foo;
public PojoSurrogate(Pojo pojo) {
this.foo = pojo.getMsg();
}
private Object readResolve() throws ObjectStreamException {
return new Pojo(foo);
}
}
It depends, if you want to use that Object in another program or another language for that matter, then yes JSON is the way to go (or XML).
But if you want to reuse that Object in another JAVA program then I guess it would be more convenient to look for a way to make possible non-serializable Objects serializable.
I haven't tested it yet, but I found a promising solution in this blog (which is in French, sorry). I'll try my best to summarize it:
what you have
say you have a class names Pojo and you want to serialize it although you don't know if it is serializable or not.
public final class Pojo {
private final String msg;
public Pojo(String msg) {
this.msg = msg;
}
public String getMsg() {
return msg;
}
public String toString() {
return "Pojo says : " + msg;
}
}
what you need
what you need is a new class that acts as a surrogate, which will take the member variables of the real Pojo and simply replace it.
public class PojoSurrogate implements Serializable {
private String foo;
public PojoSurrogate(Pojo pojo) {
this.foo = pojo.getMsg();
}
private Object readResolve() throws ObjectStreamException {
return new Pojo(foo);
}
}
the last method ( readResolve() ) is the one that will in the end give you back your new Pojo later.
The other thing you need is your own surrogate version of the ObjectOutputStream:
public class SurrogateObjectOutputStream extends ObjectOutputStream {
public SurrogateObjectOutputStream(OutputStream out) throws IOException {
super(out);
enableReplaceObject(true);
}
protected SurrogateObjectOutputStream() throws IOException, SecurityException {
super();
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException {
if (obj instanceof Pojo) {
return new PojoSurrogate((Pojo) obj);
} else return super.replaceObject(obj);
}
}
And again here the last method replaceObject() will do the magic and transform the Pojo into the serializable version PojoSurrogate to store all the information as bytes.
Serialize like this
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new SurrogateObjectOutputStream(baos);
oos.writeObject(o);
oos.flush();
oos.close();
byte[] serializedPojo = baos.toByteArray();
Deserialize normally
ObjectInputStream bais = new ObjectInputStream(new ByteArrayInputStream( serializedPojo ));
Pojo myNewPojo = (Pojo) bais.readObject();
bais.close();
Sorry, long answer.. and I hope I haven't missed anything supercool from that blog where it is easier to create a more scalable solution.. hope this helps anyway!
[EDIT:]
I tried your code with an Area object and here is how I got some thing to work (although I am not sure if this is actually working with all Areas, so you might have to test if your areas still have the same characteristics after deserialization)
AreaSurrogate
public class AreaSurrogate implements Serializable {
private final Rectangle bounds;
public AreaSurrogate(Area area) {
this.bounds = area.getBounds();
}
private Object readResolve() throws ObjectStreamException {
return new Area(bounds);
}
}
SurrogateOutputStream
public class SurrogateOutputStream extends ObjectOutputStream {
public SurrogateOutputStream(OutputStream out) throws IOException {
super(out);
enableReplaceObject(true);
}
protected SurrogateOutputStream() throws IOException, SecurityException {
super();
enableReplaceObject(true);
}
#Override
protected Object replaceObject(Object obj) throws IOException {
if (obj instanceof Area) {
return new AreaSurrogate((Area) obj);
} else {
return super.replaceObject(obj);
}
}
}
Serializer
public class Serializer {
public static byte[] serialize(Object o) throws Exception {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new SurrogateOutputStream(baos); // Magically handle Pojos !
oos.writeObject(o);
oos.flush();
oos.close();
return baos.toByteArray();
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
Object o = ois.readObject();
bais.close();
return o;
}
}
Main (to test)
public static void main(String[] args) throws Exception {
Area area = new Area(new Rectangle(0, 0, 100, 100)); // The original object, NOT SERIALIZABLE !
System.out.println(area.contains(new Rectangle(1, 1, 10, 10))); // Good as new !
System.out.print("serializing...");
byte[] pojoBytes = Serializer.serialize(area); // Serialize
System.out.println("done");
System.out.print("deserializing...");
area = (Area) Serializer.deserialize(pojoBytes); // Deserialize
System.out.println("done");
System.out.println(area.contains(new Rectangle(1, 1, 10, 10))); // Good as new !
}
In the main() I create an Area from a Rectangle which starts at Coordinate (0,0) and is 100 wide and 100 high. Then I test if the Rectangle from (1,1) with 10 width and 10 height is inside the area (which it is, forcibly). After serializing and deserializing I test if the same Rectangle is still inside the new Area.
This might be insufficient, since the new Area Object is created from a Rectangle (see AreaSurrogate). so this might not work with other Area shapes..
expected output
true
serializing...done
deserializing...done
true
Related
I'm using Gson and want to deserialize the following JSON alternatives into the same class Values. In the latter case I would like to receive a List of just one element. Is there a way to accomplish this in Gson without having to write a custom deserializer?
//Array:
{
"Value": [205.4, 13.5]
}
//Single value:
{
"Value": 205.4
}
Deserialize both into:
public static class Values {
private List<Double> Value;
}
There is no way to do this in Gson unless using custom TypeAdapter.
public class AwesomeType extends ArrayList<Double> {
...
}
public class AwesomeTypeAdapter extends TypeAdapter<AwesomeType> {
#Override
public void write(JsonWriter out, AwesomeType value) throws IOException {
...
}
#Override
public AwesomeType read(JsonReader in) throws IOException {
AwesomeType result = new AwesomeType();
if (in.peek() == JsonToken.BEGIN_ARRAY) {
in.beginArray();
while (in.peek() != JsonToken.END_ARRAY)
result.add(in.nextDouble());
in.endArray();
} else {
result.add(in.nextDouble());
}
return result;
}
}
Register this type adapter to your Gson and use this class in your model instead of List<Double>.
As #BornToCode mentioned the solution is to write a custom TypeAdapter and register it with the GsonBuilder:
public class ListTypeAdapter extends TypeAdapter<List<Double>> {
#Override
public void write(final JsonWriter writer, final List<Double> doubles) throws IOException {
writer.beginArray();
for (final double value : doubles) {
writer.value(value);
}
writer.endArray();
}
#Override
public List<Double> read(final JsonReader reader) throws IOException {
final List<Double> doubles = new ArrayList<>();
if (reader.peek() == JsonToken.BEGIN_ARRAY) {
reader.beginArray();
while (reader.hasNext()) {
doubles.add(reader.nextDouble());
}
reader.endArray();
} else {
doubles.add(reader.nextDouble());
}
return doubles;
}
}
Register it:
GSONBUILDER.registerTypeAdapter(new TypeToken<List<Double>>(){}.getType(),
new ListTypeAdapter().nullSafe());
I am using Externalization in this example. First I serialized the object into the file named "tmp" using writeExternal() method .But when I am deserializing it using readExternal() i am getting the output as follows...
default
The original car is name=Maruti
year2009
age10
The new Car is name=null
year0
age10
Here why the name and the year of the car is not serialized? And if is serialized, why i am getting null and 0 as their values...Please specify..
import java.io.*;
class Car implements Externalizable
{
String name;
int year;
static int age;
public Car()
{
super();
System.out.println("default");
}
Car(String n,int y)
{
name=n;
year=y;
age=10;
}
public void writeExternal(ObjectOutput out) throws IOException
{
out.writeObject(name);
out.writeInt(year);
out.writeInt(age);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
while(in.available()>0){
name=(String)in.readObject();
year=in.readInt();
age=in.readInt();
}
}
public String toString()
{
return("name="+name+"\n"+"year"+year+"\n" +"age" +age);
}
}
public class ExternExample
{
public static void main(String args[])
{
Car car=new Car("Maruti",2009);
Car newCar=null;
try{
FileOutputStream fout=new FileOutputStream("tmp");
ObjectOutputStream so=new ObjectOutputStream(fout);
so.writeObject(car);
so.flush();
}
catch(Exception e){System.out.println(e);}
try
{
FileInputStream fis=new FileInputStream("tmp");
ObjectInputStream oin=new ObjectInputStream(fis);
newCar = (Car) oin.readObject();
}
catch(Exception e){System.out.println(e);}
System.out.println("The original car is "+car);
System.out.println("The new Car is "+newCar);
}
}**
Get rid of the loop and the available() test. You've only written one object, so you should only read one object, so there is no reason to loop, let alone call available(). There are few correct uses of that method, and this isn't one of them.
If you extended Serializable instead of Externalizable and simply removed the read/writeExternal() methods it would work just as well.
Your main method isn't closing the ObjectOutputStream or ObjectInputStream.
I have a problem while serializing an object in Java(8). I saw many examples, but none of them work for me. The thing is that while serializing it doesn't serialize the object with its complete data. When I try to deserialize, it reads all the variables as null. I do this with Employee class. The code for Serialize.java :
public class Serialize {
private static ArrayList<Employee> emp = new ArrayList<Employee>();
public static void main(String[] args){
try{
emp.add(new Employee("Areg Hovhannisyan",5));
emp.add(new Employee("Tigran Hakobyan",15));
emp.add(new Employee("Shivanshu Ojha",11));
FileOutputStream fos = new FileOutputStream("emps.emp");
ObjectOutputStream out = new ObjectOutputStream(fos);
out.writeObject(emp);
out.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Employee.java:
import java.io.Serializable;
public class Employee implements Serializable {
private static int age;
private static String name;
public static int getAge() {
return age;
}
public static void setAge(int age) {
Employee.age = age;
}
public static String getName() {
return name;
}
public static void setName(String name) {
Employee.name = name;
}
public Employee(String name,int i) {
this.name = name;
this.age = i;
}
#Override
public String toString() {
return "Name : " + getName() + ", Age : " + getAge();
}
}
Please give an example to do this,how to deserialize and please give it with a explanation because I also want to understand how it works.
This is because your fields in class are static. Statics are implicitly transient and we can not serialize transient fields.
The only problem in your code is that age and name fields should not be static for what you intend to do...
Your code should work just by removing the two static modifiers.
Then you maybe should read about static modifier to understand why your code couldn't work.
Default serializable fields of a class are defined to be the non-transient and non-static fields.
Oracles Link
Here is stack OverFlow Link for it
As mentioned in the above comments, Statics are implicitly transient. Also as per your code if the variables are static, you'll have one vaule(which is finally added) in your Arraylist. This is the behaviour of static variable.
Please give an example to do this,how to deserialize
Code with Deserialization:
public static void main(String[] args) throws IOException,
ClassNotFoundException {
FileOutputStream fos = null;
ObjectOutputStream out = null;
FileInputStream fis = null;
ObjectInputStream in = null;
try {
emp.add(new Employee("Areg Hovhannisyan", 5));
emp.add(new Employee("Tigran Hakobyan", 15));
emp.add(new Employee("Shivanshu Ojha", 11));
fos = new FileOutputStream("emps.emp");
out = new ObjectOutputStream(fos);
out.writeObject(emp);
fis = new FileInputStream("emps.emp");
in = new ObjectInputStream(fis);
ArrayList<Employee> empRead = (ArrayList) in.readObject();
System.out.println(empRead.get(0));
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
fos.close();
}
}
public class ExternalizableClass implements Externalizable
{
public static ExternalizableClass CACHE = new ExternalizableClass(-1);
int id;
public ExternalizableClass()
{
id = (int)(Math.random() * 1000);
}
public ExternalizableClass(int i)
{
id = i;
}
#Override
public void writeExternal(ObjectOutput out) throws IOException
{
out.writeInt(id);
}
#Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
{
//id = in.readInt();
id = in.readInt();
}
public Object writeReplace() throws ObjectStreamException
{
return new Write(0);
}
private class Write extends ExternalizableClass
{
int value;
public Write()
{
}
public Write(int i)
{
value = i;
}
public Object readResolve() throws ObjectStreamException
{
return ExternalizableClass.CACHE;
}
}
#Override
public String toString()
{
return "id: " + id;
}
public static void main(String[] argv)
{
try
{
ExternalizableClass ex = ExternalizableClass.CACHE;
System.out.println(ex);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("temp.txt"));
oos.writeObject(ex);
oos.close();
}
catch (Exception e)
{
e.printStackTrace();
}
ExternalizableClass ex;
try
{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("temp.txt"));
ex = (ExternalizableClass) ois.readObject();
System.out.println(ex);
ois.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
Both ExternalizableClass and ExternalizableClass.Write class have default (non-arg) constructors. But when deserializing it, Java complains:
java.io.InvalidClassException: SeralizableTest.ExternalizableClass$Write; no valid constructor
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1772)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at SeralizableTest.ExternalizableClass.main(ExternalizableClass.java:124)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Can anyone explain what the problems are?
I suspect the problem is that it's an inner class... so it doesn't actually have a parameterless constructor. Instead, it has two constructors, one of which takes a reference to an instance of the enclosing class, and one of which takes a reference to an instance of the enclosing class and an int.
If you make it just a nested class by adding the static modifier to the class declaration (for Write) then I suspect it'll be fine, because then it won't have the implicit extra parameter on each constructor.
I'm trying to mock static method inside of static method.
I wonder if it is possible without using any framework.
Below is what I have tried.
Goal: Mock ImageIO object so that I know what to expect for return value.
class Foo {
public static SomeObject Run(String path) {
File file = new File(path);
BufferedImage buff = ImageIO.read(file);
SomeObject some = new SomeObject(buff);
return some;
}
}
I first tried using interface and create a wrapper for ImageIO.
interface ImageReader {
public BufferedImage read(File file);
}
class RealReader implements ImageReader {
#Override
public BufferedImage read(File file) {
return ImageIO.read(file);
}
}
class MockReader implements ImageReader {
#Override
public BufferedImage read(File file) {
BufferedImage buff = new BufferedImage(0,0,0);
//do whatever I like here and return the buff
return buff;
}
}
class Foo {
public static SomeObject run(String path) {
File file = new File(path);
//ImageIO wrapper
ImageReader reader = getImageReader();
BufferedImage buff = reader.read(file);
SomeObject some = new SomeObject(buff);
return some;
}
public static getImageReader() {
return RealReader();
}
}
And I tried to override static getImageReader() so that I can return MockReader object
which then call mock version of read() method:
class MockFoo {
#Override
public static getImageReader() {
return MockReader();
}
}
This is my test code:
public void TestRun() {
MockFoo foo = new MockFoo();
foo.run();
}
Then I figured I can't override static method getImageReader()......
Is there a way to achieve my goal?
One way is to change the signature of run:
public static SomeObject run(ImageReader imageReader, String path) {
// ...