[SOLVED] Class cast exception in JME RMI

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?

1 Like

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.

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).

What does this part mean?

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.

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.

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.

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

1 Like

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:

1 Like

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:

3 Likes

No rush. Happy for the help.

1 Like

Just realized I had set this aside and didn’t follow up with a PR when 3.3.0-alpha5 demonstrated the same behavior.

I’ve just pushed a PR @ https://github.com/jMonkeyEngine/jmonkeyengine/pull/1195.

2 Likes

@pspeed are you Ok with this PR?

1 Like

Yeah, I’d have merged it myself but the “All checks have failed” error scared me and I didn’t have time to look into it.

1 Like

I saw that too - it’s failing on some Android specific things. Something about native bullet libraries, if I remember correctly. Those started one or two PRs down the line before mine, and I PR’d against the most recent main branch commit at the time.

Merged it.

The Travis build was successful this time:

Yes, it seems the fail error was due to an issue with downloading OpenALSoft.

    Task :jme3-android-native:downloadOpenALSoft FAILED
    Execution failed for task ':jme3-android-native:downloadOpenALSoft'.

    > java.net.SocketException: Connection reset
1 Like