I have instantized a class that implements Serializable and I am trying to stream that object like this:
try{
Socket socket = new Socket("localhost", 8000);
ObjectOutputStream toServer = new ObjectOutputStream(socket.getOutputStream());
toServer.writeObject(myObject);
} catch (IOException ex) {
System.err.println(ex);
}
All good so far right? Then I am trying to read the fields of that object like this:
//This is an inner class
class HandleClient implements Runnable{
private ObjectInputStream fromClient;
private Socket socket; // This socket was established earlier
try {
fromClient = new ObjectInputStream(socket.getInputStream());
GetField inputObjectFields = fromClient.readFields();
double myFristVariable = inputObjectFields.get("myFirstVariable", 0);
int mySecondVariable = inputObjectFields.get("mySecondVariable", 0);
//do stuff
} catch (IOException ex) {
System.err.println(ex);
} catch (ClassNotFoundException ex) {
System.err.println(ex);
} finally {
try {
fromClient.close();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
But I always get the error:
java.io.NotActiveException: not in call to readObject
This is my first time streaming objects instead of primitive data types, what am I doing wrong?
BONUS
When I do get this working correctly, is the ENTIRE CLASS passed with the serialized object (i.e. will I have access to the methods of the object's class)? My reading suggests that the entire class is passed with the object, but I have been unable to use the objects methods thus far. How exactly do I call on the object's methods?
In addition to my code above I also experimented with the readObject method, but I was probably using it wrong too because I couldn't get it to work. Please enlighten me.
To answer your first question:
You need to use ObjectInputStream.readObject to deserialize. You cannot read individual fields from the stream*.
fromClient = new ObjectInputStream(socket.getInputStream());
Object myObject = fromClient.readObject();
Don't forget to flush the output stream when writing!
The second question is a little more complex. What the serialization mechanism does is write a class identifier to the stream followed by the serialized object data. When it deserializes it will read the class identifier and attempt to load that class (if it isn't already loaded). It will then instantiate the object using the no-arg constructor and call the private readObject(ObjectInputStream) method. Yes, that's right, it calls a private method from outside the class. Java serialization is special.
If the class cannot be found (i.e. if it's not on the classpath) then an exception will be thrown; otherwise you'll get a fully deserialized object of the correct type assuming no other errors are found.
For example, suppose you have the following classes:
class Server {
public static void main(String[] args) {
// Set up an OutputStream sink, e.g. writing to a socket (not shown)
...
ObjectOutputStream out = new ObjectOutputStream(sink);
out.writeObject(new Data("data goes here"));
out.flush();
out.close();
}
}
class Client {
public static void main(String[] args) {
// Set up an InputStream source (not shown)
...
ObjectInputStream in = new ObjectInputStream(source);
Data d = (Data)in.readObject();
System.out.println(d.getData());
}
}
class Data implements java.io.Serializable {
private String data;
public Data(String d) {
data = d;
}
public String getData() {
return data;
}
}
Now suppose you put those classes into three jars (one class per jar): server.jar, client.jar and data.jar. If you run the following commands then it should all work:
java -cp server.jar:data.jar Server
java -cp client.jar:data.jar Client
But if you do this:
java -cp server.jar:data.jar Server
java -cp client.jar Client
then you'll get a ClassNotFoundException because the client doesn't know how to find the Data class.
Long story short: the class itself is not written to the stream. If deserialization succeeds then you will have access to the object as though it had been created locally, but you will have to downcast the result of readObject to the expected type.
There is some complexity around versioning that I've ignored for now. Take a look at serialVersionUID and how to deal with changes to serializable classes if versioning is likely to be an issue.
*Not strictly true. You can call readFields inside the serializable object's readObject method (or readResolve), but you cannot call it from outside the deserialization mechanism. Does that make sense? It's a little hard to explain.
Looking at the code for ObjectInputStream.readFields(), that exception is called because the curContext field is null. You should call fromClient.readObject() before calling readFields(), as it will set the curContext. Note that readObject() will return the instance that is being serialized, which may be of more use to you.
Related
So for a homework assignment, I have a example of how to marshal data and unmarshal.
The structure they gave us was this:
Event is an interface.
Wireformat is a class that "inherits" an Event.
WireFormatWidget is a class with the actual code that has the marshal and unmarshal.
I have separate threads that handle the sending data in byte array using TCP.
What I have an issue is that when I create a Wireformat object. I run into issue with a thread trying to marshal the data.
Exception in thread "main" java.lang.NullPointerException
at myhw.WriteFormatWidget.getBytes(WriteFormatWidget.java:38)
The interface structure defines the data as a message, a type of message as an integer, a timestamp (of what I am assuming is Date and getTime of that date), and a tracker. I am not sure what the tracker is.
I am told this structure is the best method to sending data which is why I am trying to implement this code style.
The WriteFormatWidget consist of this:
private int type;
private long timestamp;
private String identifier;
private int tracker;
So for my wireformat, I created it as a class that extends WireFormatWidget and implements Event because that was the only way Eclipse did not spit an error or suggest changing WireFormatWidget or Event.
Now when I hardcode my specific wireformat, I instantiate it and it seems to not be able to call getBytes() with the hardcoded values I uses for the same variables.
public class MyWireFormat extends WireFormatWidget implements Event {
private String identifier = "here is my custom wireformat";
....
When I print out the identifier in the getBytes in WireFormatWidget, I get null and not the expected identifier I hardcoded. So I must not be "inheriting" appropriately. What am I doing wrong?
EDIT: WireFormatWidget (given)
public class WriteFormatWidget {
private int type;
private long timestamp;
private String identifier;
private int tracker;
public byte[] getBytes() throws IOException {
byte[] marshalledBytes = null;
ByteArrayOutputStream baOutputStream = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(new BufferedOutputStream(baOutputStream));
dout.writeInt(type);
dout.writeLong(timestamp);
System.out.println("getBytes using identifier: " + identifier);
byte[] identifierBytes = identifier.getBytes();
int elementLength = identifierBytes.length;
dout.writeInt(elementLength);
dout.write(identifierBytes);
dout.writeInt(tracker);
dout.flush();
marshalledBytes = baOutputStream.toByteArray();
baOutputStream.close();
dout.close();
return marshalledBytes;
}
}
I'll save space by not posting the unmarshalling portion. But its the same thing just in reverse.
The issue I am having is printing the data from the Client-side as proof of what I am sending beforehand.
So I will perform a simple test like print the type or print the identifier. It fails and I have null.
You're not initializing WireFormatWidget#identifier. It's declared but never initialized. Add a constructor to WireFormatWidget and provide a String as the identifier.
You need to implement something that implements Serializable, or implement directly Serializable (I think is simpler).
You do not specify many things about your interface event, but probably will inherit from Serializable, at least if you are going to implement standard java serialization.
If Event implements Serializable so it is ok, otherwise if you use another serialization method you need to specify more about it.
Assuming that you implement Serializable you need to create a ByteBuffer and call to writeObject. To create the stream you can check for example Java Serializable Object to Byte Array, so joining all:
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream stream = new ObjectOutputStream(bos);
stream.writeObject(yourinstancetoserialize);
out.flush();
byte[] yourBytes = bos.toByteArray();
...
Probably you will need to implement the writeObject directly. In that case you use the ObjectOutputStream methods to serialize the properties, check them in https://docs.oracle.com/javase/7/docs/api/java/io/ObjectOutputStream.html for example.
private void writeObject(java.io.ObjectOutputStream stream) throws IOException {
stream.writeInt(this.type);
stream.writeLong(this.timestamp);
stream.writeBytes(this.identifier); or stream.writeChars(this.identifier);
stream.writeInt(this.tracker);
...
}
I want to read an object from file using ObjectInputStream.
Here is what the readObject method looks like inside:
public void readObject(ObjectInputStream inbos) throws IOException {
try {
GameModel gm = (GameModel) inbos.readObject();
} catch (IOException ex) {
Logger.getLogger(GameDeserializer.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(GameDeserializer.class.getName()).log(Level.SEVERE, null, ex);
}
}
My GameModel class has a readResolve method. GameModel class is also a singleton.
public Object readResolve() throws ObjectStreamException {
System.out.println("At read resolve method ");
GameModel themodel = getGameModel();
System.out.println("Reading the file : " + themodel.toString() + themodel );
return themodel;
}
The problem is it is not reading the object right.
It is reading it as a pointer.
I need help please.
Your implementation of readResolve() will replace whatever you had written in the stream with the current singleton, so no data from the stream is actually used. (assuming the getGameModel() gets the singleton instance)
Explaining: The ObjectInputStream will instantiate and deserialize a new instance of GameModel, then call readResolve(), which if your current implementation will tell the stream to use the old singleton instead.
If that's what you are trying to do, you should also consider writing an empty writeObject() to avoid writing unnecessary data to the stream.
If that was not what you had in mind and GameModel is really supposed to be a singleton your choices are:
Using readResolve() to copy data from the "just read game model" to the singleton
Using readResolve() to replace the current singleton instance (sounds dangerous)
Any number of tricks with writeReplace/readResolve using a replacement object (like GameModelReplacement) to hold the data you want to save/restore;
About readObject(): It's not clear in your question if that readObject is in GameModel. I'm assuming it's not. However if it is, the statement (GameModel) inbos.readObject(); makes no sense as the GameModel is the current object (this). If that's the case do something like this:
public class GameModel {
private void readObject(ObjectInputStream inbos) throws IOException {
// do nothing
}
private void writeObject(ObjectOuputStream out) throws IOException {
// do nothing
}
private Object readResolve() throws ObjectStreamException {
// discarding serialized gamemodel, and using the singleton.
return getGameModel();
}
}
Okay, so I am trying to do my network packet handling in Java using classes. For reading data from my stream I use a DataInputStream. My reading thread for my server looks like this:
public void run()
{
while(client.isActive())
{
try{
handle(is.readShort());
}catch (IOException e){
client.stop(e);
break;
}
}
}
Now I've got a method handle:
public void handle(short id) throws IOException
{
InPacket packet = null;
try {
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id);
}catch (Exception e){
e.printStackTrace();
}
if (packet!=null){
packet.handle(this);
}
else{
throw new IOException("Invalid packet");
}
}
I try to instantiate a new class using the
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id);
line.
In ClassUtils this is that function:
public static <T> T newInstance(Class<? extends T> type, String className) throws
ClassNotFoundException,
InstantiationException,
IllegalAccessException {
Class<?> clazz = Class.forName(className);
Class<? extends T> targetClass = clazz.asSubclass(type);
T result = targetClass.newInstance();
return result;
}
My problem is: when I try to get that class with only part of the name (I try to get it by "InPacket1", while the class is called "InPacket1Connect"), it can't find it. Is it possible to do this in Java, and if so how? If not, what method do you recommend for handling my network packets?
An alternative approach would be to use a map (or enum) which maps the id to the full class name.
Pulling in the stuff from the comments, ensure that this mapping class is available as a jar (or may be in the same jar which contains the implementations of the packet handlers) as your "messaging layer" jar.
Like this, maybe?
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id+"Connect");
^^^^^^^^^^
(but I may have misunderstood your question)
Why can you not create the full class name?
packet = ClassUtils.newInstance(InPacket.class, "server.client.InPacket"+id + "Connect"
You could implement the functionality you seem to be asking for - a kind of "fuzzy" classname matching - by writing your own classloader. The classloader could search some directories for class files partially matching the type.
My feeling is that this is potentially a brittle solution, there's a danger of loading unexpected classes. I prefer Nim's suggestion of explicitly having a mapping table if you can't use an algorthimic classname generator.
I'm trying to implement loading and saving for a game I'm working on.
What I want to save is:
A char[][] (bidimensional array/matrix)
An ArrayList<Entity>
Entity is a super class for Dragon, Hero and Item. All three of these types can be contained at once in the ArrayList.
So far I have this:
package logic;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public final class LoadAndSave {
public static final transient boolean available = false;
public static final boolean serialize(Object obj) {
// Write to disk with FileOutputStream
FileOutputStream saveFile;
try {
saveFile = new FileOutputStream("game.sav");
} catch (FileNotFoundException e) {
return false;
}
// Write object with ObjectOutputStream
ObjectOutputStream objOut;
try {
objOut = new ObjectOutputStream(saveFile);
} catch (IOException e) {
//
return false;
}
// Write object out to disk
try {
objOut.writeObject(obj);
} catch (IOException e) {
return false;
}
return true;
}
public static final Object load() {
FileInputStream fileIn;
try {
fileIn = new FileInputStream("game.sav");
} catch (FileNotFoundException e1) {
return null;
}
// Read object using ObjectInputStream
ObjectInputStream objIn;
try {
objIn = new ObjectInputStream(fileIn);
} catch (IOException e) {
return null;
}
// Read an object
Object obj;
try {
obj = objIn.readObject();
} catch (IOException e) {
return null;
} catch (ClassNotFoundException e) {
return null;
}
return obj;
}
}
I think the code is pretty self-explanatory. Now for my questions:
Will this code suffice?
Do I need to implement specific serialization methods for Dragon, Item and Hero?
How will the serialization mechanism deal with the fact that I have an Entity vector full of types that are not Entity, but derived classes?
Thanks for your time!
OK, all seems to be well, except for one the ArrayList. It is either not getting saved or loaded (null pointer exception when calling size()).
What may this be due to?
If you want the entire structure to be serializable, then you'll need to make the parts serialiable as well. What this means in practice is that you need to make your Dragon, Hero, and Item classes implement Serializable. It's just a marker interface, so you only need to add implements Serializable. Some ides (at least eclipse, anyway) may complain that you should add a private long SerialVersionUID which may or may not optimize the serialization a bit - in any case it's not strictly necessary.
This requirement is recursive - any of their subparts that are custom or non-serializable objects have to be taken care of as well, so for example if your Item class looks like this
public class Item implements Serializable {
private String s;
private MyClass c;
..
then you'll also need to make MyClass Serializable, any of it's instance variables, etc etc.
I don't see any reason for specific serialization methods for Dragon, Item and Hero unless you require some very special stuff that the default serialization mechanism cannot handle.
(Of course the classes need to be serializable as mentioned by Steve B)
You already have a lot of code so I suspect that you've already run some tests. Have you faced certain problems? Or how does it come that you are asking this?
Update:
I've noticed some aspects in your code which are not directly related to your question but may anyway be of interest for you:
Do you really mean to use Vector? Does your application make use of multithreading and serialization is required? If not you might prefer to use ArrayList or so instead.
The way you handle exceptions is quite strange. Perhaps you are only doing so as this is an example... You should not suppress exceptions by simply returning true or false. If you expect calling methods to be interested in exceptions you should simply add the exception to the methods signatur (throws...) and let the calling method care about it. If you feel this is not appropriate wrapping such exceptions in custom exceptions, which are more expressive in the context, might be an option. If you don't care about the exception at all wrapping it into a runtime exception is also possible. In case of success your method might simply return nothing...
I have an array that I have created from a database ResultSet. I am trying to Serialize it so that I can send it over a socket stream. At the moment I am getting an error telling me that the array is not Serializable. The code I have is down below, the first part is the class to create an object for the array:
class ProteinData
{
private int ProteinKey;
public ProteinData(Integer ProteinKey)
{
this.ProteinKey = ProteinKey;
}
public Integer getProteinKey() {
return this.ProteinKey;
}
public void setProteinKey(Integer ProteinKey) {
this.ProteinKey = ProteinKey;
}
}
The code to populate the array:
public List<ProteinData> readJavaObject(String query, Connection con) throws Exception
{
PreparedStatement stmt = con.prepareStatement(query);
query_results = stmt.executeQuery();
while (query_results.next())
{
ProteinData pro = new ProteinData();
pro.setProteinKey(query_results.getInt("ProteinKey"));
tableData.add(pro);
}
query_results.close();
stmt.close();
return tableData;
}
And the code to call this is:
List dataList = (List) this.readJavaObject(query, con);
ObjectOutputStream output_stream = new ObjectOutputStream(socket.getOutputStream());
output_stream.writeObject(dataList);
And the code recieving this is:
List dataList = (List) input_stream.readObject();
Can someone help me serailize this array. All I can find in forums is simple arrays(EG. int[]).
I tried to add the serializable to the class and the UID number but got java.lang.ClassNotFoundException: socketserver.ProteinData error message. Does anyone now why?
Thanks for any help.
Basically you need that the classes you want to serialize are implementing Serializable. And if you want to avoid the warning related to the serial you should have also a long serialVersionUIDfor each one, that is a code used to distinguish your specific version of the class. Read a tutorial like this one to get additional info, serialization is not so hard to handle..
However remember that serialization is faulty when used between two different versions of the JVM (and it has some flaws in general).
Just a side note: the interface Serializabledoesn't actually give any required feature to the class itself (it's not a typical interface) and it is used just to distinguish between classes that are supposed to be sent over streams and all the others. Of course, if a class is Serializable, all the component it uses (instance variables) must be serializable too to be able to send the whole object.
Change your class declaration to:
class ProteinData implements Serializable {
...
}
I would have thought as a minimum that you would need
class ProteinData implements Serializable
and a
private static final long serialVersionUID = 1234556L;
(Eclipse will generate the magic number for you).
in the class.