Converting a byte stream to an Object - java

I have a Packet class (com.lab.tracking.Packet) in an Android project. I need to send this packet via UDP to a Server, that has an exactly copy of that Packet class (com.server.serverTracking.Packet).
The android app converts the Packet into a byte stream, and then it sends it to the server. The server receives the byte stream correctly, but when it tries to convert it to a Packet, it throws an exception:
java.lang.ClassNotFoundException: com.lab.tracking.Packet
I understand that. The server is trying to convert this object to a com.lab.tracking.Packet, instead of a com.server.serverTracking.Packet).
The conversion from byte stream to Object is:
public static Object toObject(byte[] dataReceived) {
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(dataReceived);
ObjectInputStream ois = new ObjectInputStream(bis);
obj = ois.readObject();
} catch (IOException ex) {
ex.printStackTrace();
} catch (ClassNotFoundException ex) {
ex.printStackTrace();
}
return obj;
}
How could I avoid this? Both classes are exactly the same, so I think the problem is in the complete name (or ID, or whatever).
Thanks!

To expand on djg's answer, the problem is that your Packet classes are not "exactly the same" because they are in different packages.
So the solution would be to get rid of com.server.serverTracking.Packet and move com.lab.tracking.Packet to a common library that both the android app and the server side code depend on.
That being said, I would recommend against using Java object serialization between and android app and the server. If your Packet changes in any significant way (new member variables, etc.) with new releases, you will likely break all previous versions. At the very least, you should explicitly specify a serialVersionUid.
A better solution would be to design a structure for the packet byte array, and use a factory class or constructor that parses the byte array into a Java object.

Put the packet implementation in a core library that both the android project and server depend on.

Related

Send Data between client and server as a byte array

I am trying to send encrypted data between a client and server. Due to the RSA encryption its in Byte array form. This means I have had to change the way I send data. I curently cant get it working, Ill leave my method (sendMessage) below which is what handles the sending of the message, If anyone could tell me what I am doing wrong that would be great :)
public void sendMessage(byte[] msg){
if(msg.equals("null")){
}
else{
try{
ByteArrayOutputStream f = new ByteArrayOutputStream(CSocket.getOutputStream());
out = new PrintWriter(f);
out.write(msg);
countSend++;
}catch (IOException e){
System.out.println("ERROR");
}
}
}
Sorry should have clarified, essentially CSocket is a socket I have opend and I want to send msg through the socket. The issue I have specifically with this code is It says that: OutputStream can not be converted to int on the line where I creat the ByteArrayOutputStream object f and No suitable method found for write(byte[]) on the line out.write(msg);
Thanks for the clarification! Please see https://docs.oracle.com/javase/10/docs/api/java/io/ByteArrayOutputStream.html#write(byte%5B%5D,int,int)
The write method in ByteArrayOutputStream for byte[] needs two more arguments. Something like the following might work:
out.write(msg, 0, msg.length);
Please let me know if this is useful.
I think I fixed my issue now. Its probibably not the most efficient way of doing it but essentially I encode the byte array in a format that means I wont loose any data. This means I send it in this encoded format and then on the receving end I just simply decode it. Works so much better with print writer doing it this way.
OutputStream f = CSocket.getOutputStream();
out = new PrintWriter(f);
String encodedmsg = new String(msg, "ISO-8859-1"); // ISO-8859-1 is supposed to give every character a unique representation so I shouldent loose any data during encoding and decoding
out.write(encodedmsg);

NotSerializableException with java.awt.geom.Area

I'm creating a game where all locations of 'blocks' are stored in the variable block_area - an object of class Area. My game has been running correctly for a week now, and I've decided to implement a save and load feature where I save block_area to a file Drifter, with this as my code:
Area block_area; // Later initialized
void saveArea()
{
try
{
FileOutputStream fos = new FileOutputStream(savefile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(block_area);
oos.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
void loadArea()
{
try
{
FileInputStream fis = new FileInputStream(savefile);
ObjectInputStream ois = new ObjectInputStream(fis);
block_area = (Area)ois.readObject();
ois.close();
}
catch(Exception e)
{
e.printStackTrace();
}
}
However, this is my very first time writing and reading an OBJECT to a file, so I don't know much about it. When I try to save the object to the file, it gives me this error:
java.io.NotSerializableException: java.awt.geom.Area
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at Drifter.saveArea(Drifter.java:58)
at Drifter.keyPressed(Drifter.java:315)
...
If anyone can tell me how I can go about writing and reading an object with a file, the help will be greatly appreciated.
TL;DR How do I write the contents of an Area object to a file and read it?
ALSO I have a few follow-up questions:
Is ObjectInputStream the best course of action here? I have seen a few answers where people recommend using XML, and JSON, but I can never find the time to learn about them, and would prefer to stick to a pure Java method (without any third party tools)
Is there any other method of saving an object's information to an external source that I can use instead of file handling?
EDIT - I should also mention that my class implements Serializable
The exception is pretty self explanatory NotSerializableException: java.awt.geom.Area . Any object that you want to serialize must implement the Serializable interface. java,awt.geom.Area does not. Any attributes of that class must also implement Serializable, be a primitive, or be defined as transient.
I'd suggest either Figuring out a way to read Area into an object that does implement Serializable. When you read it back out, you can construct a new Area object. This is probably what the JSON/XML method mentioned in the comments is doing. The added benefit of a human readable storage format is that you can edit it in a text editor. You won't be able to do that with the binary output of a serialized object`.

Sending java object to python and receive it back

Consider an object in java which implements Serializable. I want to send that object to a python code on TCP socket. I am serializing object and sending on TCP by using :
//socket connection code
PySessionObject object = new PySessionObject();
object.setMethodCall(PyServerMethodConstant.SETATTRIBUTE);
object.setAttributeName(name);
object.setAttributeValue(value);// value is of object type which also implements Serializable
os = sChannel.socket().getOutputStream();
oos = new ObjectOutputStream(os);
oos.writeObject(object);
oos.flush();
os.flush();
//socket closing and exception handling
Now I want to convert this byte stream into object in python perform some operation on that object and send it back to java world and deserialize it again. For this purpose I come to about javaobj-py3, with this everything is fine until I pass LinkedHashMap in setAttributeValue(). In Python I am doing this:
total_data=b''
while True:
data = self.clientsocket.recv(8192)
if not data: break
total_data += data
pyobj = javaobj.loads(total_data)
For this I am getting exception as:
RuntimeError: Unknown OpCode in the stream: 0x8 (at offset 0x14C)
What will be cause? Is it like opcodes are not found for "something"? Is anyone can suggest any other idea to convert byte stream send from java into object in python world perform some operation on that object and send it back to java world and deserialize it again.
You can convert the object to a JSON string and then send over the wire.
To convert object to json
new GSONBuilder().create().toJSON(obj);
To convert json to object
new GSONBuilder().create().fromJSON(jsonString, YouObject.class);
I prefer using GSON for converting a object to json and reverse in java. In python you can use json library. The methods are
json.loads(string) and json.dumps(object)

How to Serialize/Deserialize an object without implementing Serializable interface?

If a mail is send to my inbox, I recieve a message, and I'm inserting the contents into DB.
I have a org.springframework.integration.core.Message something like follows:
public void receive(Message<?> message)
{
//I am inserting message contents into DB
}
Now in the event of failure, I wanted to have fail safe recovery mechanism, what I am thinking is to serialize the Message object into a file and later deserialize and update to DB.
Question
1. In this situation how to serialize the Message object?
2. Other than serialization any other mechanism that can be used?
EDIT
I have not done Serialization before, I heard like the class should implements Serializable in order to use ObjectOutputStream, in this case I don't want to create a subclass of Message, So how to serialize Message to File?
Sure, there are many serialization mechanisms apart from the jvm one.
XML
JSON
BSON
MessagePack
protobufs
...
Some of them are text-based, some are binary. All have drawbacks and pluses. Text-based ones are human-readable, binary ones are faster and take up less space.
There are java libraries that handle all the above formats: JAXB (XML), Jackson (JSON), etc.
In this situation how to serialize the Message object? Other than serialization any other mechanism that can be used?
Extract all the data you need from the Message and save it. You can do this in any manner you choose.
You can deserialize it by populating a new Message with the data you saved.
I don't know if I probably understood it al right.. but assuming Message is not much more than lots of strings and some integers you can just use directly an ObjectOutputStream and write it to a file (binary) and then readin later. Why not?
Message e = new Message();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("whatever");
oos.writeObject(message);
// read in
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("whatever");
Message e = (Message) ois.readObject();

What could lead to the creation of false EOF in a GZip compressed data stream

We are streaming data between a server (written in .Net running on Windows) to a client (written in Java running on Ubuntu) in batches. The data is in XML format. Occasionally the Java client throws an unexpected EOF while trying decompress the stream. The message content always varies and is user driven. The response from the client is also compressed using GZip. This never fails and seems to be rock solid. The response from the client is controlled by the system.
Is there a chance that some arrangement of characters or some special characters are creating false EOF markers? Could it be white-space related? Is GZip suitable for compressing XML?
I am assuming that the code to read and write from the input/output streams works because we only occasionally gets this exception and when we inspect the user data at the time there seems to be special characters (which is why I asked the question) such as the '#' sign.
Any ideas?
UPDATE:
The actual code as requested. I thought it wasn't this due to the fact that I had been to a couple of sites to get help on this issue and they all more or less had the same code. Some sites mentioned appended GZip. Something to do with GZip creating multiple segments?
public String receive() throws IOException {
byte[] buffer = new byte[8192];
ByteArrayOutputStream baos = new ByteArrayOutputStream(8192);
do {
int nrBytes = in.read(buffer);
if (nrBytes > 0) {
baos.write(buffer, 0, nrBytes);
}
} while (in.available() > 0);
return compressor.decompress(baos.toByteArray());
}
public String decompress(byte[] data) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
ByteArrayInputStream in = new ByteArrayInputStream(data);
try {
GZIPInputStream inflater = new GZIPInputStream(in);
byte[] byteBuffer = new byte[8192];
int r;
while((r = inflater.read(byteBuffer)) > 0 ) {
buffer.write(byteBuffer, 0, r);
}
} catch (IOException e) {
log.error("Could not decompress stream", e);
throw e;
}
return new String(buffer.toByteArray());
}
At first I thought there must be something wrong with the way that I am reading in the stream and I thought perhaps I am not looping properly. I then generated a ton of data to be streamed and checked that it was looping. Also the fact they it happens so seldom and so far has not been reproducable lead me to believe that it was the content rather than the scenario. But at this point I am totally baffled and for all I know it is the code.
Thanks again everyone.
Update 2:
As requested the .Net code:
Dim DataToCompress = Encoding.UTF8.GetBytes(Data)
Dim CompressedData = Compress(DataToCompress)
To get the raw data into bytes. And then it gets compressed
Private Function Compress(ByVal Data As Byte()) As Byte()
Try
Using MS = New MemoryStream()
Using Compression = New GZipStream(MS, CompressionMode.Compress)
Compression.Write(Data, 0, Data.Length)
Compression.Flush()
Compression.Close()
Return MS.ToArray()
End Using
End Using
Catch ex As Exception
Log.Error("Error trying to compress data", ex)
Throw
End Try
End Function
Update 3: Also added more java code. the in variable is the InputStream return from socket.getInputStream()
It certainly shouldn't be due to the data involved - the streams deal with binary data, so that shouldn't make any odds at all.
However, without seeing your code, it's hard to say for sure. My first port of call would be to check anywhere that you're using InputStream.read() - check that you're using the return value correctly, rather than assuming a single call to read() will fill the buffer.
If you could provide some code, that would help a lot...
I would suspect that for some reason the data is altered underway, by treating it as text, not as binary, so it may either be \n conversions or a codepage alteration.
How is the gzipped stream transferred between the two systems?
It is not pssible. EOF in TCP is delivered as an out of band FIN segment, not via the data.

Categories

Resources