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
I have been going through a very simple example to set up a Remote Method Invocation application and while going through the client side code I am not able to understand one code as shown below. Definitely, gaps in my knowledge because I though an interface cannot have objects unless you use Anonymous Inner Class. So in the code below how did we creat an object of Remote Interface. It seems some sort of type-casting to me if I had to guess.
import java.rmi.*;
public class HelloClient {
public static void main(String args[]) {
try {
if (args.length < 0) {
System.err.println("usage: java HelloClient string …\n");
System.exit(1);
}
HelloInterface hello = (HelloInterface)Naming.lookup("//localhost/Hello");
This last line is what I am not able to understand what exactly is happening here with (HelloInterface) part?
HelloInterface hello = (HelloInterface)Naming.lookup("//localhost/Hello");
This Naming.lookup() call inspects the RMI Registry running in the localhost for a binding under the name "Hello".
It returns an Object that has to be cast to whatever remote interface you're expecting it to be.
You can then use that object to call the remote methods defined in the interface.
I thought an interface cannot have objects unless you use Anonymous Inner Class.
I have no idea what you're talking about here. Any class can implement an interface. This is rather basic.
So in the code below how did we create an object of Remote Interface
We didn't. We got it as a return value from the Registry, where it was put by the server.
It seems some sort of type-casting to me if I had to guess.
No need to guess. That's exactly what it is. There is only one 'sort' of typecasting, and this is how you write it. This is also rather basic.
HelloInterface hello = (HelloInterface)Naming.lookup("//localhost/Hello");
What is this mean ?
It is basically looking for an object in the server object pool registered with a name //localhost/Hello. this is called JNDI name
Depending on the type of server, this can be configured within the server configuration file.
This is from the Minecraft server source code, also called the Minecraft Bukkit API, now you know as much as I do.
There is an interface called Server:
public interface Server extends PluginMessegeRecipient {
public String getVersion();
}
PluginMessageRecipient is an interface also.
There is a class called Bukkit that instantiates Server:
public final class Bukkit {
private static Server server;
}
Inside methods in the Bucket class they invoke methods from the server object. For example:
server.getVersion();
The thing is, there is no code for getVersion in the Server interface, just a method signature. There is also no code in the PluginMessageRecipient interface nor does it extend anything.
I have read all the questions and answers on SO that say I need an anonymous class or an inner class and this does not seem to fit those solutions.
There is a class called Bucket that instantiates Server:
Actually Bucket doesn't instantiate Server. The class Bucket contains a reference to a Server. You haven't shown how that got set so we don't know the actual class.
However, it is guaranteed that what is assigned to that reference (Bucket.server), assuming it's not null, is a an object of some concrete class that implements Server. That class will provide an implementation of getVersion() and that is what is being called.
Bukkit is just a Modding API. If you want to implement Bukkit, you need to create such an instance yourself and pass it there.
Take for example the unit tests that Bukkit includes:
https://github.com/Bukkit/Bukkit/blob/f210234e59275330f83b994e199c76f6abd41ee7/src/test/java/org/bukkit/TestServer.java#L77
A real implementation that allows you to run a Bukkit server is Spigot.
If I recall correctly, the particular concrete class that's being selected is determined at runtime via reflection. Because Minecraft is not open source, all the developers have are the obfuscated compiled class files to work with.
The code searches through each class file within the minecraft jar, searching for a class that matches certain conditions, and then, using a bytecode library, force that class to implement that interface.
For example, let's say that the following (obfuscated) class was the real Server class within the Minecraft code
class a {
String x_x317() {
return q_q98;
}
static a a_a1;
static String q_q98 = "1.9.4";
}
In this case, the method x_x317 returns the version string. The tool that allows them too hook into this class might do it based on the following conditions:
The class has default access
The class has only one default access static reference to itself
The class has only one default access static String field.
The class has a single method, that has default access, that returns String, and the returned value is the FieldRef found in 3.
This generally returns only one class. In the case that multiple are returned (usually in the dev phase of the new Bukkit version), they get more specific with their conditions to ensure that they only get the right class returned. They do this for every field, class, and method they need to identify.
Since they now know which exact class is the Server class, they can go ahead and make changes to it. First they would need to implement the interface
class a implements org.bukkit.Server
And then implement the method
class a implements org.bukkit.Server {
String x_x317() {
return q_q98;
}
public String getVersionNumber() {
return x_x317();
}
static a a_a1;
static String q_q98 = "1.9.4";
}
Now, we have a class that conforms to the Bukkit API.
When they need to instantiate that class, they just do something along the lines of
Server server = findAndTransformServerClassFromMinecraftJar();
// ...
Server findAndTransformServerClassFromMinecraftJar() {
// load classes from jar
// map them to the appropriate interfaces
// transform and hook the required classes and methods
Class<?> serverClass = doTheFirstThreeSteps();
return (Server) serverClass.newInstance();
}
I'm trying to create a simple example with Java EE JMS.
If i try to receive an ObjectMessage, i need to have exactly the same path (packagename) as the other project, which sends the ObjectMessage.
For example i have in my sender project a class called Person in the packege "org.queue.sender" and exactly the same class in my receiver project in the package "org.queue.receiver".
As already said, if i try to get the objectmessage i get the following Exception:
java.lang.ClassNotFoundException: org.queue.sender.Person
If i create a new package in my receiver project named org.queue.sender and transfer the class Peron there, then it run. but i think i couldn't be the really solution.
Is there a better solution?
From the JavaDoc:
An ObjectMessage object is used to send a message that contains a serializable object in the Java programming language ("Java object"). It inherits from the Message interface and adds a body containing a single reference to an object. Only Serializable Java objects can be used.
So, objects passed via ObjectMessages must be Serializable i.e. it must be the same class and the exact same package.
If you need more flexible handling of messages I suggest that you use e.g. TextMessage and serialize/deserialize the objects using e.g. JSON or XML.
ObjectMapper mapper = ... ; // Get hold of a Jackson ObjectMapper
session.createTextMessage(mapper.writeValueAsString(myPojo));
// and on the receiving side
TextMessage message = ....; // From the message receiver
MyPojo myPojo = mapper.readValue(message.getText(), MyPojo.class);
I am getting the following serialization error and I am trying to read my object that I saved to a file
java.io.InvalidClassException: com.testGame.scoreCard; Incompatible class (SUID): com.testGame.scoreCard: static final long serialVersionUID =-5895378336422852901L; but expected com.testGame.scoreCard: static final long serialVersionUID =0L;
at java.io.ObjectInputStream.verifyAndInit(ObjectInputStream.java:2376)
at java.io.ObjectInputStream.readNewClassDesc(ObjectInputStream.java:1658)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:683)
at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:1799)
at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:787)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1999)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:1956)
But what I don't get is why scoreCard is serialized in the first place? The class(object) that I am writing and reading is serialized and does not call or make use of scoreCard class. Why would it complain about that class? Is there a way to see why this scoreCard is involved? ( I am using eclipse btw)
Thank you
Are you perhaps serializing an inner class of ScoreCard? They have secret references to the containing object.
Could it be that class that you are trying to restore depends indirectly on ScoreCard, through another class for example?
To see dependencies in Eclipse you can click on a class name or method name and press Ctrl+Shift+G, it will show you all the places where class or method is used.
Another way to discover dependencies is to click on a method name and press Ctrl+Alt+H, it will show you call graph that you can discover further.
In shared.jar I have:
abstract class MyParent {
}
abstract class MyClass {
MyParent getFoo();
}
server.jar contains
abstract class MyChild extends MyParent {
}
abstract class MyClassConcrete {
MyParent getFoo() {return new MyChild();}
}
client.jar:
MyParent foo = myClass.getFoo();
If all 3 jars are in one classloader everything works well.
But client and server are in different JVMs while:
JVM-1 contains: server.jar, shared.jar
JVM-2 contains: client.jar, shared.jar
Client makes call to server. Server returns MyConcreteClass and Java fails to deserialize it (ClassNotFoundException).
What I wanna do:
Server serializes class and sends data and set of class's ancestors
Client finds the narrowest ancestor it may deserialize.
And everything is ok: we have instance of MyParent on the client and that is what we need.
I can't believe there is no such engines. Do you know one?
I am sure remote call should be as similar to local calls as possible.
Thanks.
Actually I found solution and made a special package to support it:
MyParent has to me marked with special SerializableParent annotation. This annotation means any child class should be "converted" to MyParent before remoting engine may serialize it and transfer it over the wire. By setting this annotation not only you tell the system MyParent exists on remote JVM but also hierarchy tree does not require polymorphism: if child overrides parent's method it would not be available on remote system because only data but code could be sent.
Before sending result engine should find narrowest ancestor annotated as SerializableParent
Object that should be serialized to XML (with XStream for example) and deserialized back using parent class as alias for child. To prevent "unknown fields" error Xstream has to be hacked by overriding wrapMapper and shouldSerializeMember.
You got "serializable parent" to be transfered
An object implementing the java.io.Serializable interface can use the writeReplace() and readResolve() methods to substitute another object for the one being serialized/deserialized. I can see this being used to address your problem. However, I have not tried this myself.