I have two simple applications: client and server. Client encrypts (simple AES) custom object and sends it through TCP socket, as bytes, to the server. Server decrypts those bytes and calls the method that recreates this object, like this:
private static Object getObjectFromBytes(byte[] credentials) throws IOException, ClassNotFoundException{
ByteArrayInputStream bis = new ByteArrayInputStream(credentials);
ObjectInput in = null;
Object credentialsObj = null;
try {
in = new ObjectInputStream(bis);
credentialsObj = in.readObject();
} finally {
bis.close();
in.close();
}
return credentialsObj;
}
On the client side, when I'am encrypting this object, it is of type mds.hm5.client.ITU_Credentials. On the server side, when I'm decrypting it and converting back to object, it should be mds.hm5.tokenservice.ITU_Credentials. Instead I'am getting the following exception:
java.lang.ClassNotFoundException: mds.hm5.client.ITU_Credentials
He is looking for this object by the old classpath. Why is it happening and how should I fix it?
Additional information:
Here is how I convert this object to byte array on the client side:
private static byte[] getBytesFromObject(Object credentials) throws IOException{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput out = null;
byte[] newBytes = null;
try {
out = new ObjectOutputStream(bos);
out.writeObject(credentials);
newBytes = bos.toByteArray();
} catch (IOException e) {
e.printStackTrace();
} finally {
out.close();
bos.close();
}
return newBytes;
}
The reason why I use generic type Object is because I am going use those methods to convert/encrypt/decrypt multiple types. Is it the proper way?
On the client side, when I'am encrypting this object, it is of type mds.hm5.client.ITU_Credentials.
So that's what it is in the serialized stream.
On the server side, when I'm decrypting it and converting back to object, it should be mds.hm5.tokenservice.ITU_Credentials.
No it shouldn't. It should be the same as when you serialized it [unless you have taken certain magic steps, which clearly you haven't. Without those magic steps there is no magic, and nothing to connect mds.hm5.client.ITU_Credentials with mds.hm5.tokenservice.ITU_Credentials whatsoever]. You have two different classes with the same name and different packages, one in each location. They aren't the same.
He is looking for this object by the old classpath.
You are confused between CLASSPATH and package name. They aren't the same thing. It is looking for this object by its actual package name. What else can it possibly do?
The object output stream doesn't serialize the class itself but only its state (the field values). The receiver needs the class file on it's classpath.
It is possible to transfer the class too. You'll have to find (or write) a classloader that can load the class from your connection. If you have an URL for your classfile then you could use the URLClassloader. Then you don't have to add the class to your classpath.
Your client neeeds to have in its classpath the .class files that define the object. What you are doing is serializing/deserializing the instance, not the class.
Late, but it may be useful for someone in the future:
I wanted to send an object Message whose package was entities in the client side, but in the server side this Message class was not nested within a entities package, so this Exception was thrown. It may be dumb but I spent many hours figuring out this.
Related
How can i load a class that is not found when reading object from ObjectInputStream
Example
InputStream pis = new InputStream();
ObjectInputStream ois = new ObjectInputStream(pis);
Object o = null;
try{
o = ois.readObject();
}
catch(ClassNotFoundException ex){
//How to try to load a class to read object again?????
o = ois.readObject();
}
Thanks,
TH
The classes of the objects you try to deserialize should already be on your classpath when trying to deserialize objects.
If you encounter this, I guess you can't really do much at runtime. Instead you can use this to detect if you are still missing classes from your classpath, and add those to your project and classpath during developing.
Use an RMIClassLoader at both ends, and pay attention to its documented requirements at the sending end.
The ClassNotFoundException could also be thrown if the class has moved.
Let's say you serialize a class instance. Later, the class is moved, due to some refactoring. Then you are stuck as the old class fully qualified name is not longer valid. No way to get your object back from the stream.
I'm working on a HTTP server in Java, which for testing purposes is running under Windows 8.1.
The way it's coded makes it so when a certain parameter is set, it changes the header of the HTTP file and sends the file through the socket with something that works kind of like:
socket.outputStream.write(filter.read());
Assume that the communication works fine, since I have tested it with various other filters and it works perfectly.
One of the filters is supposed to grab the HTML file, zip it and then send it to the client, without creating the file in the server machine. This is the header:
"HTTP/1.1 200 OK\nContent-Type: application/zip\nContent-Disposition: filename=\"" + request + ".zip\"\n";
Afterwards, I set my filter to a class I created (which is copied below) and send the file. My problem is that even though the server is definitively sending data, the client only downloads an empty zip file, with nothing inside.
I've been stuck with this issue for a few days, I can't seem to figure out what's wrong. I think that there's something wrong with how I create the entry or maybe how I close the outputs. I can't be sure.
I'd really appreciate any advice that could be given to me on this issue. Thanks for your attention.
class ZipFilterInputStream extends FilterInputStream
{
protected ZipFilterInputStream(InputStream inputToFilter) throws IOException
{
super(inputToFilter);
//Get the stuff ready for compression
ByteArrayOutputStream out = new ByteArrayOutputStream();
ZipOutputStream zout = new ZipOutputStream(out);
zout.putNextEntry(new ZipEntry("file.html"));
//Compress the stream
int data = in.read();
while (data != -1)
{
zout.write(data);
data = in.read();
}
zout.closeEntry();
zout.finish();
//Get the stream ready for reading.
in = new ByteArrayInputStream(out.toByteArray());
out.close();
}
public int read() throws IOException
{
return in.read();
}
}
E.g. There is some app (outside of my src control) that produces thousands and thousands of serialized Map instances stored as /dev/shm/{some Map-ID}.ser . They are serialized using the plain old java.io.* package.
Can the code here, which is within my src control (to de-serialize Map instances), benefit from using NIO instead of plain old java.io.* package? Or, theoretically, given that these IO operations are on /dev/shm, is any NIO advantage presumed to be negligible?
private Map<Integer,String> deserializeMapFrKernelSHM(String shmKey) {
Map<Integer,String> retM = null;
try {
FileInputStream frKernelSHM = new FileInputStream("/dev/shm/"+shmKey+".ser");
ObjectInputStream in = new ObjectInputStream(frKernelSHM);
retM = (Map<Integer,String>) in.readObject();
System.out.println("Linux IPC shmop(GET) de-serialized Map<K,V> from /dev/shm/"+shmKey+".ser");
}catch (Exception e) {
e.printStackTrace();
}
return(retM);
}
Not really. It's almost impossible to combine Object Serialization with NIO.
You could try a BufferedInputStream around the FileInputStream.
Okay, so my issue is that i have alot of programs that i am using in java that use the exact same array of objects but i dont want to keep recreating this array every time that i write a new program. Is there a way to save an array of objects for use in other java programs. if so how?
If you are a beginner you should serialize the array of objects into a file. The convention is to name your serialized file name-of-file.ser
try
{
FileOutputStream fileOut = new FileOutputStream("card.ser");//creates a card serial file in output stream
ObjectOutputStream out = new ObjectOutputStream(fileOut);//routs an object into the output stream.
out.writeObject(array);// we designate our array of cards to be routed
out.close();// closes the data paths
fileOut.close();// closes the data paths
}catch(IOException i)//exception stuff
{
i.printStackTrace();
}
to deserialze it use this:
try// If this doesnt work throw an exception
{
FileInputStream fileIn = new FileInputStream(name+".ser");// Read serial file.
ObjectInputStream in = new ObjectInputStream(fileIn);// input the read file.
object = (Object) in.readObject();// allocate it to the object file already instanciated.
in.close();//closes the input stream.
fileIn.close();//closes the file data stream.
}catch(IOException i)//exception stuff
{
i.printStackTrace();
return;
}catch(ClassNotFoundException c)//more exception stuff
{
System.out.println("Error");
c.printStackTrace();
return;
}
To serialize an object, create an ObjectOutputStream and call writeObject.
// Write to disk with FileOutputStream
FileOutputStream f_out = new
FileOutputStream("myobject.data");
// Write object with ObjectOutputStream
ObjectOutputStream obj_out = new
ObjectOutputStream (f_out);
// Write object out to disk
obj_out.writeObject ( myArray );
Reference
You can serialize many kinds of objects. Yes, an array is a object too (#see Array class). If you don't wan't the limitations of Arrays, you could use one of the Container classes (eg LinkedList) too. The serialization works the same way.
Write a class that manages this array. Put this class, along with classes it depends on, in its own JAR. Re-use JAR across multiple programs.
If you use Eclipse, you can do that by creating a new Java project (let's call it project OM - from Object Model) and putting the Foo and FooManager classes there. Then in each project you want to reuse the objects, in the Build Properties of the project add the OM project to the class path and to the exports tab. That's it.
Consider these two functions:
Function A takes inputStream as parameter.
public void processStream(InputStream stream)
{
//Do process routine
}
Function B loads a file content to pass it to Function A as InputStream.
pulic void loadFile()
{
File file =new File("c:\\file.txt");
//Pass file as InputStream
}
How can I pass file from Function B to Function A as InputStream without reading it on first hand?
I did something like this:
File file = new File("c:\\file.txt");
DataInputStream stream= new DataInputStream(new FileInputStream(file));
This generated the exception below:
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.io.DataInputStream
EDIT:
loadFile() is passing the InputStream as RMI response.
The following should work just fine
processStream(new FileInputStream(file));
You should only not attempt to serialize an InputStream instance by ObjectOutputStream like as
objectOutputStream.writeObject(inputStream);
which you're apparently doing in processStream() method. That's namely exactly what the exception is trying to tell you. How to solve it properly depends on the sole functional requirement which you omitted from the question.
Update as per the comment
I am passing the InputStream as an RMI response.
There's the problem. You cannot pass non-serializable objects around as RMI response, let alone unread streams. You need to read the InputStream into a ByteArrayOutputStream the usual IO way and then use its toByteArray() to get a byte[] out of it and pass that instead. Something like:
InputStream input = new FileInputStream(file);
ByteArrayOutputStream output = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
for (int length = 0; (length = input.read(buffer)) > 0;) {
output.write(buffer, 0, length);
}
byte[] bytes = output.toByteArray(); // Pass that instead to RMI response.
Be careful with large files though. Every byte of a byte[] eats one byte of JVM's memory.
That exception seems to indicate that you are calling the processStream method on a remote object using something like RMI? if that is the case, you will need to re-visit what you are doing. sending streams of data over RMI is not an easy thing to do. if you are guaranteed to be using small files, you could copy the file data to a byte[] and pass that to the remote method call. if you need to process larger files, however, that will most likely cause memory issues on the client and/or server. in that case, you should use something like rmiio, which provides utilities for streaming data over RMI.
You could just pass the FileInputStream ?
processStream(new FileInputStream(yourFile));
The reason you are getting the exception is because DataInputStream is intended to read primitive Java types