Class cast exception in JME RMI


#1

My project has a pretty complex networking layer, so I’m taking a close look at JME’s RMI system before getting any deeper into piles of handlers and message types.

In one part of my server I have the following:

RmiHostedService rmi = netServer.getServices().getService(RmiHostedService.class);
HeartbeatImpl heartbeat = (HeartbeatImpl) rmi.getRmiRegistry(conn).getLocalObject(Heartbeat.class);

This produces the following exception (irrelevant sections removed):

java.lang.ClassCastException: Cannot cast com.jme3.network.service.rmi.RmiRegistry$SharedObject to myproject.networking.Heartbeat
	at java.base/java.lang.Class.cast(Class.java:3606)
	at com.jme3.network.service.rmi.RmiRegistry.getLocalObject(RmiRegistry.java:197)
	at com.jme3.network.service.rmi.RmiRegistry.getLocalObject(RmiRegistry.java:187)
	at myproject.server.network.NetworkManager.lambda$init$0(NetworkManager.java:150)
        ...

I took a look at RmiRegistry, and sure enough, on line 197:

return type.cast(local.byName.get(name));

where type is the class parameter and local.byName is a map with a type parameter of SharedObject, which is just a container for the actual shared object + metadata.

Unless I’m missing something, this could be fixed to produce its intended behavior by changing RmiRegistry:197 to:

return type.cast(local.byName.get(name).object);

Anyone want to take a look at this?


#2

It may be true. I think no one hits this because there is usually no need to ask the registry for the object that you gave it… since you already had it.


#3

True, but in a non-trivial server setup it’s nice to be able to toss the shared objects at the RMI service and grab them later when you need them - it tracks connection -> object associations already, so setting them as connection data is just more work that you don’t need to be doing (and isn’t type safe besides).


#4

What does this part mean?


#5

Well, once you’ve shared them you’ve got pretty much two options… stick them in a collection, or add them as user data on the connection as a custom connection attribute.


#6

Yeah, it’s the “not type safe” part that confused me. To me it’s just as “type safe” as the RMI stuff… you’ll get a class cast exception if you try to retrieve the wrong type.


#7

You’re right - it’s been a long day. In either case it’s up to you to pass the right class type and (probably) cast to the concrete type in your own code.


#8

I just tried out the proposed change above on a fresh pull from GitHub and it resolves the issue.


#9

I mean, HostedConnection’s type is implicit but:
HeartBeatImpl heartbeat = conn.getAttribute(“heartbeat”);

…will make the compiler cast for you just like the RMI is casting internally. Because of the T parameter.

Nice. Any chance for a PR? :slight_smile:


#10

Sure thing, but it’ll come later tonight or tomorrow - believe it or not, I don’t have a personal GitHub account. I have one for my day job, but I use BitBucket for my own projects so the need hasn’t really come up yet. I’ve been meaning to spend some time here and there hunting down issues in jME though, so it’s time to make one. :slight_smile:


#11

No rush. Happy for the help.