java.io.InvalidClassException in serialization - java

after reading for serialization, i tried to perform an experiment on the example provided in the book. Following code has some variation and this is basically picked from SCJP book.
import java.io.FileInputStream;
public class SerializationTest {
public static void main(String[] args) {
Collar c = new Collar(4);
Dog d = new Dog(c, "Sheru", 32);
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = new FileOutputStream(
"C:\\Users\\dell\\Desktop\\NewDir\\DogState.txt");
oos = new ObjectOutputStream(fos);
oos.writeObject(d);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
oos.close();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// ***************************************************************************************************
// //
Dog restore = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream(
"C:\\Users\\dell\\Desktop\\NewDir\\DogState.txt");
ois = new ObjectInputStream(fis);
restore = (Dog) ois.readObject();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
fis.close();
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
System.out.println("after: dog name: "+ restore.name +" , collar=" + restore.getCollar());
System.out.println("Animal material is:" + restore.getWeight());
}
}
// Intentionally added parameterized constructor so that default constructor is not called.
class Animal{
int weight = 42;
public Animal(int weight) {
this.weight = weight;
System.out.println("animal constructor");
}
}
class Dog extends Animal implements Serializable {
String name;
transient Collar collar;
public Collar getCollar() {
return collar;
}
public void setCollar(Collar collar) {
this.collar = collar;
}
public int getWeight() {
return weight;
}
public void setWeight(int weight) {
this.weight = weight;
}
public Dog(Collar collar, String name, int weight) {
super(weight);
System.out.println("Dog constructor");
this.collar = collar;
this.name = name;
}
}
class Collar {
int size;
public Collar(int size) {
System.out.println("Collar constructor");
this.size = size;
}
}
Here my question is why InvalidClassException is occuring, Please explain what is the root cause of exception.
Current output is
Collar constructor
animal constructor
Dog constructor
java.io.InvalidClassException: Dog; Dog; no valid constructor
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:39)
Caused by: java.io.InvalidClassException: Dog; no valid constructor
at java.io.ObjectStreamClass.<init>(Unknown Source)
at java.io.ObjectStreamClass.lookup(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:18)
Exception in thread "main" java.lang.NullPointerException
at SerializationTest.main(SerializationTest.java:54)
If i remove Animal constructor and comment out the super(weight) in Dog constructor, then output is
Collar constructor
Dog constructor
after: dog name: Sheru , collar=null
Animal material is:42
I understand this output, and i also get the fact that during de-serialization serialzable class's superclass constructor is called but here no default constructor is present, so exception occured. But why this exception occur i want to know.

The exception is thrown by the time you try to read the from the file:
at java.io.ObjectInputStream.readObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:39)
The stack trace clearly indicates that your program aborts when it attempts to read an object. What may get you confused is the second stack trace referring to the write:
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at SerializationTest.main(SerializationTest.java:18)
But you seem to have skipped this very important line:
Caused by: java.io.InvalidClassException: Dog; no valid constructor
Java stacktraces can be nested, one exception can lead to another; and this here is a litte ackward. As a matter of fact, during the serialization of an object it is already computed that there is no default constructor. Here's an excerpt of the involved source code:
...
cons = getSerializableConstructor(cl);
...
} else if (cons == null) {
deserializeEx = new InvalidClassException(name, "no valid constructor");
}
This means that during the write, it is already clear that there is no valid constructor. However, the exception is not thrown but serialized along with the object. Later, when deserializing, this code is called:
void checkDeserialize() throws InvalidClassException {
if (deserializeEx != null) {
InvalidClassException ice =
new InvalidClassException(deserializeEx.classname,
deserializeEx.getMessage());
ice.initCause(deserializeEx);
throw ice;
}
}
Here, a "real" exception is thrown, but the cause of it is set to be the one stored during serialization of the object.
This mechanism is only found in SUN/Oracle's Java implementation; OpenJDK clearly throws an exception by the time a read is attempted, and does not keep around a stack trace from writing.

The non-Serializable base class Dog must have an accessible default constructor. When you comment out the Dog(weight) constructor, you force the compiler to provide one, and when you leave it in the compiler doesn't provide one.

There is a rule that the parent class of the serializing class or any associated class to that must be implementing Serializable.In your case, when you remove thesuper(weight); then it checks for default constructor and runs properlyBut also if you put class Animal implements Serializable then also code runs properly.

Related

IllegalArgumentException when trying to get reference to Field using Reflection

I am trying to loop through many ArrayLists of custom classes with the same code and thought using reflection would make it easier. I am running into an issue when I try to get a reference to each field however. Here is a small representation of the code I am trying to run. (my code is different but the essentials are there):
import java.lang.reflect.*;
import java.util.ArrayList;
public class Stack {
public ArrayList<Custom1> cust11;
public ArrayList<Custom1> cust12;
public ArrayList<Custom1> cust13;
public ArrayList<Custom2> cust21;
public ArrayList<Custom2> cust22;
public ArrayList<Custom2> cust23;
public static void main(String args[]) {
Stack stack = new Stack();
}
public Stack() {
cust11 = new ArrayList<Custom1>();
cust12 = new ArrayList<Custom1>();
cust13 = new ArrayList<Custom1>();
cust21 = new ArrayList<Custom2>();
cust22 = new ArrayList<Custom2>();
cust23 = new ArrayList<Custom2>();
doReflect();
}
public void doReflect(){
Field[] fields = this.getClass().getFields();
for(Field f : fields) {
if(f.getName().contains("cust1")) {
try {
ArrayList<Custom1> temp = (ArrayList<Custom1>)f.get(cust11);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
class Custom1{
public Custom1() {}
}
class Custom2{
public Custom2() {}
}
When it gets to
ArrayList<Custom1> temp = (ArrayList<Custom1>)f.get(cust11);
I get
java.lang.IllegalArgumentException: Can not set java.util.ArrayList field
Stack.cust11 to java.util.ArrayList
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(Unknown Source)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(Unknown Source)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(Unknown Source)
at java.lang.reflect.Field.get(Unknown Source)
at Stack.doReflect(Stack.java:33)
at Stack.<init>(Stack.java:25)
at Stack.main(Stack.java:14)
How can I do this?
I should have used
ArrayList<Custom1> temp = (ArrayList<Custom1>)f.get(this);

How to make this if statement true so it does not catch an Exception?

I'm trying to write an if statement that both catches an exception and does not catch an exception, I have caught the exception but I cannot figure out how to make the condition true so that it does not catch the exception and returns the desired value. Here is the code:
Main
package QuestionEditor;
public class Main {
public Main() {
super();
}
public static void main(String[] args) {
Wolf wolfExample = new Wolf();
try {
Food vegFood = new Food("Spinach");
System.out.println("************Wolf Exception example************");
wolfExample.eat(vegFood);
//wolfExample.eat(vegFood);
} catch (Exception e) {
// TODO: Add catch code
e.printStackTrace();
}
System.out.println("************Wolf Non-Exception example************");
Food Meat = new Food("Steak");
System.out.println("Wolves eat " + wolfExample.eat(Meat));
}
}
Animal
package QuestionEditor;
abstract public class Animal
{
String name;
int age;
String noise;
abstract public void makeNoise();
public String getName() {
return name;
}
public void setName(String newName) {
name = newName;
}
abstract public Food eat(Food x) throws Exception;
}
package QuestionEditor;
public class Carnivore extends Animal
{
public Food eat(Food x) throws Exception
{
if (x instanceof Meat) {
return x;
} else {
throw new Exception("Carnivores only eat meat!");
}
}
public String toString(Food x) {
return x.toString();
}
public void makeNoise()
{
noise = null;
}
public String getNoise()
{
return noise;
}
}
Food
package QuestionEditor;
public class Food {
//field that stores the name of the food
public String name;
//constructor that takes the name of the food as an argument
public Food(String name){
this.name = name;
}
public String getName() {
return name;
}
}
Meat
package QuestionEditor;
public class Meat extends Food
{
public Meat(String name) {
super(name);
}
public String getName() {
return super.getName();
}
}
Wolf
package QuestionEditor;
public class Wolf extends Carnivore
{
Wolf()
{
name = "Alex";
age = 4;
}
public void makeNoise()
{
noise = "Woof!";
}
public String getNoise()
{
return noise;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public Food eat(Food x) throws Exception
{
if (x instanceof Meat) {
return x;
} else {
throw new Exception("Carnivores only eat meat!");
}
}
}
Output
************Wolf Exception example************
java.lang.Exception: Carnivores only eat meat!
************Wolf Non-Exception example************
at QuestionEditor.Wolf.eat(Wolf.java:34)
at QuestionEditor.Main.main(Main.java:15)
Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - unreported exception java.lang.Exception; must be caught or declared to be thrown
at QuestionEditor.Main.main(Main.java:25)
C:\Users\lee-pc\AppData\Local\NetBeans\Cache\8.2\executor-snippets\run.xml:53: Java returned: 1
It wants me to catch Meat as an exception but I want to make it so that Meat is not an exception and relates to the Meat condition in the if statement which looks like this:
public Food eat(Food x) throws Exception
{
if (x instanceof Meat) {
return x;
} else {
throw new Exception("Carnivores only eat meat!");
}
}
Should be true of this:
Food Meat = new Food("Steak");
System.out.println("Wolves eat " + wolfExample.eat(Meat));
The desired output would be:
************Wolf Exception example************
java.lang.Exception: Carnivores only eat meat!
************Wolf Non-Exception example************
Wolves eat Meat
I understand that I have made an error but I'm struggling to figure out how to resolve it, any help would be great, thanks.
The reason why you don't get "Wolves eat Meat" printed, but an Exception is that you still need a try - catch block around every call to .eat() even when you know that the Exception won't be thrown.
The exception you are getting here before the line is printed is a RuntimeException because the code is not compilable
The second reson why this is not working, is that the "meat" you are giving the wolf is of the type Food and not Meat:
Food meat = new Food("Steak"); // no matter what name you give the food, it is still of the class Food
These little changes will make it work:
Food meat = new Meat("Steak"); // you create a Meat object and store it in a Food variable (so to speak)
try{
System.out.println("Wolves eat " + wolfExample.eat(meat)); // must be surrounded by a try-catch block
}catch(Exception ex){
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex); // better way to log the exception than ex.printStackTrace();
}
BTW: variables should start with a small letter (Food meat instead of Food Meat .. otherwise how do you know if Meat is the class or your variable? ;)
EDIT
another sidenote: your class Food should override the toString() method to be properly printable. Otherwise System.out.println(meat) will just end up in something like com.my.package.Meat#5113de03
If a method has the potential to throw a checked exception, this is declared in its signature. If you call a method that declares the potential to throw an exception, you must either provide a handler for that exception or declare that you, too, could throw it. The fact that you, as you're writing the exercise, happen to know that you should not get the exception in this case does not relieve you of this requirement.
What you have to do is put the code that calls the method in a try block, and provide a catch block for the checked exception that the method declares it could throw (Exception in this case). This does not mean that the exception will get thrown - in this case it won't - but Java insists on knowing what it should do if it were thrown.
Some people - notably the Spring community - don't really like this behavior, so they use unchecked exceptions for just about everything. (Unchecked exceptions are those derived form RuntimeException or Error, though Error is generally reserved for more severe situations.) The original design of Java, though, was to ensure that every checked exception should eventually reach a handler.

Java Object Serialization nested objects

I was studying Serialization in Java when I came across saving the state of objects which are not serializable and are referenced in Class(instance variables) to be serialized. In the following code, I am having class Dog (Serializable) which has reference to class Collar(not serializable); which in turn has reference to class Color (not serializable). I am getting error despite trying all the possibilities. This is the latest code I came up with:
class Color {
private String colorName;
public String getColorName() {
return colorName;
}
public void setColorName(String colorName) {
this.colorName = colorName;
}
Color(String color) {
this.colorName = color;
}
}
class Collar {
private Color color;
private int size;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Color getColor() {
return color;
}
public void setColor(Color color) {
this.color = color;
}
Collar(int size, Color color) {
this.size = size;
this.color = color;
}
}
class Dog implements Serializable {
Dog(String breed, Collar collar) {
this.breed = breed;
this.collar = collar;
}
private String breed;
public String getBreed() {
return breed;
}
public void setBreed(String breed) {
this.breed = breed;
}
public Collar getCollar() {
return collar;
}
public void setCollar(Collar collar) {
this.collar = collar;
}
transient private Collar collar;
private void writeObject(ObjectOutputStream os) {
try {
os.defaultWriteObject();
os.writeInt(this.getCollar().getSize());
os.writeUTF(this.getCollar().getColor().getColorName());
os.close();
} catch (IOException ex) {
Logger.getLogger(Dog.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void readObject(ObjectInputStream is) {
try {
is.defaultReadObject();
int size = is.readInt();
String colorName = is.readUTF();
this.setCollar(new Collar(size, new Color(colorName)));
is.close();
} catch (Exception ex) {
Logger.getLogger(Dog.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class App0001 {
public static void main(String[] args) {
try {
Dog d = new Dog("Great Dane", new Collar(3, new Color("RED")));
//System.out.println(d.getCollar().getColor().getColorName());
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("obj.ser"));
os.writeObject(d);
os.close();
ObjectInputStream is = new ObjectInputStream(new FileInputStream("obj.ser"));
d = (Dog) is.readObject();
System.out.println(d.getCollar().getColor().getColorName());
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
And I am getting following error:
java.io.IOException: Write error
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:260)
at java.io.ObjectOutputStream$BlockDataOutputStream.drain(ObjectOutputStream.java:1847)
at java.io.ObjectOutputStream$BlockDataOutputStream.setBlockDataMode(ObjectOutputStream.java:1756)
at java.io.ObjectOutputStream.writeNonProxyDesc(ObjectOutputStream.java:1257)
at java.io.ObjectOutputStream.writeClassDesc(ObjectOutputStream.java:1211)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1395)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1158)
at java.io.ObjectOutputStream.writeFatalException(ObjectOutputStream.java:1547)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:333)
at Serialization.App0001.main(App0001.java:121)
This is not a production code. This is just for practice and understanding.
You must not close the streams in readObject and writeObject! If you do so, the next write/read attempt fails.
Usually, streams (as other resources) should be treated as follows:
If your method owns the stream, i.e. your method opened it - close it
in the same method (usually this is done in a try-with-resource
statement).
If your method does NOT own the stream, i.e. it got the stream passed from somewhere else (usually passed via method parameter), don't close it as you don't know what the owner of the stream wants to do with it after your method returns.
When writing to a stream, the "Write error" in an IOException occurs, if the stream is closed.
Analyzing your code, I see that you have a custom writeObject method in your class Dog. In that you must not close the stream, as it is needed for continued writing. So just remove the line
os.close();
in your writeObject method. Oh, and also remove the line
is.close();
in the readObject method.
Ok, I will explain it a bit more. You have the following code in your main method:
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("obj.ser"));
os.writeObject(d);
os.close();
Here you are creating the stream, using it, and afterwards you close it. This is the correct place to close it, as this is the responsible place for the stream.
Imagine, you have a nested structure of serializable objects, whose class definitions all contain a custom writeObject method. When calling the writeObject method of an ObjectOutputStream, it walks through the object graph with calling the writeObject method of each object. The ObjectOutputStream is controlling the write order, and it also write control bytes itself. Creating and closing must be done outside (as you already did).

InstantiationException when Instantiate generic type in java

I have been trying to get this to work for a while and I have searched high and low for answers (including here). But I can't figure it out.
So here the code (a bit minimized):
public class Event<T> {
public MessageType msgType;
public int layer;
public int gameObjectId;
public String name;
public float value;
public int senderId;
public T ext;
public Event(Class<T> classType) {
if(classType != null) {
try {
ext = classType.newInstance(); //this is the failing line
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
msgType = MessageType.NONE;
layer = TypeHandler.lAll;
gameObjectId = -1;
name = null;
value = -1;
}
}
public class DataExtension {
public float[] values;
public String[] string;
public Object[] objects;
public boolean[] boolens;
}
This is the problem:
Event<DataExtension> mSelectionEvent;
mSelectionEvent = new Event<DataExtension>(DataExtension.class, MessageType.SELECTED);
This give me the following exception:
java.lang.InstantiationException: se.plainentertainment.bagl.v2.core.Event$DataExtension
at java.lang.Class.newInstance0(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at se.plainentertainment.bagl.v2.core.Event.<init>(Event.java:85)
at se.plainentertainment.bagl.v2.core.SelectionHandler.<init>(SelectionHandler.java:46)...
So, the class that I'm trying to instantiate should meet all the requirements, right? It has a default constructor and it's not abstract in any way. Why do I get this error?
Thanks in advance!
Event$DataExtension
This is an inner class. Is it static? I'm going to go with a hunch and say no. Which means it contains a reference to the containing Event (implicitly), which means you likely can't instantiate it via newInstance.
Try setting it to be a static inner class, or move it out of the class it if it doesn't need to be tied to the event object.

How to assign new object to existing one

I've got a problem with reading an object from file..
in main, I made eshop end call a method loadshop.
MyShop eshop = new MyShop();
eshop.loadShop("eshop.txt");
and also I'm getting the shop object from file.
#Override
public void loadShop(String filename) {
try{
ObjectInput out = new ObjectInputStream(new FileInputStream(filename));
MyShop shop = (MyShop)out.readObject();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
But I just can't figure out how to assign "shop" to "eshop"
Thank you for any answer..:-) (Sorry for my English)
Just redesign, you don't need to write
MyShop eshop = new MyShop();
Instead, write
MyShop eshop = MyShop.loadShop("eshop.txt");
and make the loadShop method static. And make it return the MyShop instance, if it isn't already doing that.
If this is not an option, it is still better to get that instance through a hack than to write manual copying code:
public class MyShop {
private MyShop readShop;
public MyShop getReadShop() { return readShop; }
public void loadShop(String fName) {
try {
ObjectInput out = new ObjectInputStream(new FileInputStream(filename));
this.readShop = (MyShop)out.readObject();
out.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
You'd use this like
MyShop tempShop = new MyShop();
tempShop.loadShop();
MyShop eshop = tempShop.getReadShop();
Make your loadShop method a static method. Make the method return the MyShop object. Call it on the MyShop class. Assign the return value to eshop. Example:
public class MyShop {
public static MyShop loadShop(String filename) {
// ...
MyShop shop = (MyShop)out.readObject();
// ...
return shop;
}
}
Where you call the method:
MyShop eshop = MyShop.loadShop("eshop.txt");
Simply edit all eshop's fields, to match shop.

Categories