readobject method throws ClassNotFoundException - java

I'm trying to pick up Java and wanted to test around with Java's client/server to make the client send a simple object of a self defined class(Message) over to the server. The problem was that I kept getting a ClassNotFoundException on the server side.
I think the rest of the codes seem to be alright because other objects such as String can go through without problems.
I had two different netbeans projects in different locations for client and server each.
Each of them have their own copy of Message class under their respective packages.
Message class implements Serializable.
On the client side, I attempt to send a Message object through.
On the server side, upon calling the readObject method, it seems to be finding Message class from the client's package instead of it's own. printStackTrace showed: "java.lang.ClassNotFoundException: client.Message" on the server side
I have not even tried to cast or store the object received yet. Is there something I left out?

The package name and classname must be exactly the same at the both sides. I.e. write once, compile once and then give the both sides the same copy. Don't have separate server.Message and client.Message classes, but a single shared.Message class or something like that.
If you can guarantee the same package/class name, but not always whenever it's exactly the same copy, then you need to add a serialVersionUID field with the same value to the class(es) in question.
package shared;
import java.io.Serializable;
public class Message implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}

The reason is, that the readObject() in ObjectInputStream is practically implemented as:
String s = readClassName();
Class c = Class.forName(s); // Here your code breaks
Object o = c.newInstance();
...populate o...

Related

Dynamic class creation - Java

Is there a way to dynamically create a class having a string containing the code of the class or maybe adding a method in the same way to an existing class previously created?
Use case scenario: A student is doing an exam in which he has to write some methods without an IDE (So he submits a simple string). What i want to achieve is a way to execute a simple unit test on his submission. For example a clickable button to run unit test back-provided by the professor.
Sorry for my bad english and thanks in advance!
The KIT (a university in Karlsruhe, Germany) has created a tool to test programming tasks from students. May you look at it here
The student will be submitting Java source code, not byte code. Java source code has to be compiled into byte code using a Java compiler before it can be loaded by a classloader. You could do this by invoking the compiler programmatically (see this answer). Loading byte code of this new .class file at runtime can be done like this:
class NetworkClassLoader extends ClassLoader {
String host;
int port;
public Class findClass(String name) {
byte[] b = loadClassData(name);
return defineClass(name, b, 0, b.length);
}
private byte[] loadClassData(String name) {
// load the class data from the connection
. . .
}
}
(example from here, thanks #Robert).
Once you have an instance you could feed it to your testing app to run some tests and get results.
It would be easiest to have the submitted class implement an interface you define and have your testing code test against that interface. In that way your test will compile beforehand and can still handle the dynamically compiled & instantiated submission at runtime.

How to subclass SubethaSmtp SMTPClient class

I am trying to develop a simple SMTPclient for testing purposes using the SubethaSmtp client package. i want to use the SMTPClient class instead of the SmartClient class for more control but i have not been able to figure out how to write mail data using SMTPClient, the only OutputStream exposed to public or external subclasses is the one for sending commands, the ones for sending data (after sending the DATA command) is exposed only to classes in the same package (SmartClient).
am i missing something here? i would like to know how a direct subclass of SMARTClient can written to work around this problem.
Looks like you are correct, you cannot simply extend the SMTPClient and get access similar to the one that SmartClient has, being a same-package class.
At this point you can either:
1) Fork your own version of the app from https://github.com/voodoodyne/subethasmtp and do whatever the hell you like with it, or
2) Go all the way and implement your own version of SMTPClient, as the package protected SMTPClient.dotTerminatedOutput;, used by SmartClient.dataWrite() actually is just instantiated like so
...
this.rawOutput = this.socket.getOutputStream();
this.dotTerminatedOutput = new DotTerminatedOutputStream(this.rawOutput);
...

RMI: serializable and remote objects

I have a certain problem: I'm using RMI to communicate between server and client.
public class RemoteMap
extends java.rmi.server.UnicastRemoteObject
implements RemoteMapInterface {
private TreeMap<String, GeneralSprite> sprites;
...
This is my remote object. But I want the client to be able to change this object's content. And after the change the server can execute some operation based on this.
Example at the client side:
map = (RemoteMapInterface) (registry.lookup("map"));
map.getSprites.get("object1").setDx(-1);
I'm using serialiable on the GeneralSprite, but I guess it passed by value. So when I did some changes at the GeneralSprite, it wasn't transported to the server . Do I have to make GeneralSprite to an Remote object too? Or is it even possibly?
Thanks in advance, and sorry for my bad english, I hope you can understand.
Everything which does not implement the Remote interface, whether directly or indirectly, will get serialized for the remote method invocation. So it’s a “call-by-copy” behavior. You can implement a new Map which implements Remote, but you can also add a method like setDx(String spriteName, int value) to your RemoteMapInterface and implement it as sprites.get(spriteName) .setDx(value); on the server side.

Sending an Object over a network using Java

I am trying to send an object in java over a physical network (not over localhost) but it seems I have something wrong.
The interface to the object (client and server have this):
public interface distributable extends Serializable {
public void test();
}
The Object I am trying to send (only server has this):
class ObjectToSend implements distributable {
public ObjectToSend() {
}
public void test() {
system.out.println("worked!");
}
}
Server:
private ObjectToSend obj = new ObjectToSend();
obj_out_stream.writeObject(obj);
obj_out_stream.flush();
Client:
private distributable ReceivedObj = null;
try {
ReceivedObj = (distributable) obj_in_steam,readObject();
} catch (ClassNotFoundException e) {
System.err.println("Error<w_console>: Couldn't recieve application code!");
}
ReceivedObj.test();
Everything was working when the ObjectToSend class implemented Serializable and I wasn't using an interface because all my classes were in one directory so the client 'knew' about the object. Now I want it to work across a physical network so the client only has the interface to the object. It seems that client can not receive the object as the exception is thrown every time.
As the other answers suggest, the Client also has to know the class of the object you want to send.
Usually, one creates three packages/projects for such a classic client-server example:
Common: Code that is used by client and server; the class definition of the objects you want to send from the server to the client belongs here
Client: All code only the client needs to know about
Server: All code only the server needs to know about
To be able to serialize and deserialize objects with objectinput/outputstream the classes must implement Serializable.
Also the deserializer must be able to find the classes on the classpath that you are trying to deserialize since this is embedded in the Serialized form.
If you want the client to have only the interface -- at compile time -- then you'll need to download the actual class from the server at run-time.
Jini (aka Apache River) makes this easy.
It's supposed to be like this. What can you do with a class whose code you don't have?
Have a look here: stackoverflow.com/questions/8175052/java-polymorphism-my-teacher-claims-you-can-distribute-an-executable-object-thr

Adding Metadata to Java RMI

I'm trying to create a system that will, on every RMI call,
1) gather some data about the current local system state (let's say the system time)
2) serialize it and transparently add it to the data sent over the wire with the call (ie, without changing the signature of the stub method being called)
3) deserialize it on the other side and take some action (let's say logging it to a file)
4) do the same thing in reverse when the method returns
I've was trying at first to do this with AspectJ, adding a pointcut at java.rmi.server.RemoteRef's invoke method that would allow me to add the metadata to the params Object array, but I've now discovered that AspectJ can't advise already-compiled code, which makes a lot of sense.
So, what's the right way to do this?
Well, I am not sure if I am getting enough context from what you are saying, but I think you could write the metadata upon serialization/deserialization of objects passed to and received from the server.
For instance, let's say you server is returning Jedi instances. And Jedi is a Serializable class. Then you could use the writeObject() and readObject() methods (as explained in the Java Serialization Specification) to write whatever special additional information that you may need at the client/server side.
For instance:
public class Jedi {
....
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.writeObject(new Date());
stream.defaultWriteObject();
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
Date sysDate = (Date) stream.readObject();
System.out.println(sysDate);
stream.defaultReadObject();
}
}
The only problem as that you would be forced to do this for every serializable object you interchange with your server.
You could also investigate RMI/JERI in the Jini 2 project. JERI stands for Java Extensible Remote Invocation protocol, i.e. you can customize it in numerous ways.

Categories

Resources