Android: How to avoid ClassCastException: org.jivesoftware. smack.util.PacketParser Utils$2?

Hi,

I’m new here, and I apologize if this gets asked a lot. I’m using Smack 3.2.0 on Android 2.3 and am trying to implement PubSub.

I can create connections, log in, create nodes, but cannot subscribe. I always get

java.lang.ClassCastException: org.jivesoftware.smack.util.PacketParserUtils$2 at org.jivesoftware.smackx.pubsub.Node.subscribe(Node.java:151)

String jid = “sean@my.openfire.local”;

LeafNode ln = null;

ln = (LeafNode) pubsubMgr.getNode(node); // gets a valid Node, this is fine

ln.subscribe(jid); // ClassCastException here

Node is created with the following config form

ConfigureForm f = new ConfigureForm(FormType.submit);

f.setPersistentItems(true);

f.setDeliverPayloads(true);

f.setAccessModel(AccessModel.open);

f.setPublishModel(PublishModel.open);

f.setSubscribe(true);

f.setNodeType(NodeType.leaf);

In a regular, non-Android app, my code works fine, but not on Android. One thing I am doing is specifying using bks keystore in ConnectionConfiguration, since Android does not support jks, but I have no idea why this ClassCastException occurs.

I was reading the source code of PacketParserUtils.java and it says somewhere in the comments of parseProperties method that

ClassCastExceptions will occur when both the sender and receiver of the packet don’t have identical versions of the same class. I am not sure how to trace where the problem is, though.

Anyone have any clue on how to resolve this? Any suggestions will be welcome, as I am more than willing to modify the code to get it to run properly on Android.

Thanks!

This problem is caused by the smack.providers file not being read from your classpath. Without this file, all incoming packets will be read by the default provider into the default packet extension, which is PacketParserUtils$2.

The exception occurs of course because the pubsub code is trying to cast to a pubsub specific extension which would be read by one of the pubsub providers.

1 Like

Thanks for the clarification. I wasn’t sure why that was happening. I did find http://community.igniterealtime.org/docs/DOC-1945 earlier, but I’ve yet to try this. Anyone tried this yet?

I’ll give it a shot in the next few days and report back.

That is meant to solve a different issue. In a normal java environment, the smack.providers file is on the classpath by default as it is containted in the smackx.jar. I suspect that the Android classloader doesn’t work the same way.

I know what you mean. However, for now, and to get it to run properly on Android, I added a method to ProviderManager to load this from an external file. Then I recompiled the JARs and put smack.providers on the phone’s SD card. Before making a connection, I load the smack providers from that file and it seems to work fine. Not the best approach, but it works.

Thanks for your comments!

You will be interested in SMACK-286, which allows for a vm argument to specify where the providers file is. I have it scheduled for the next release since there is already a patch included.

Hi Rcollier,

I have the same problem when calling node.subscribe(jid).

W/System.err(12961): java.lang.ClassCastException: org.jivesoftware.smack.packet

.DefaultPacketExtension cannot be cast to org.jivesoftware.smackx.pubsub.Subscription

Right now I am able to publish and receive the result from the listener when the node is created by the same user. But I would like to be able to have other users to receive the same update as well.

Can you be more speicifc how I can apply the patch on Android? I appreciate your help.

Regards,
Calvin

You need to make the appropriate code changes and then either create a new smack jar with that code, or put the altered class file on the classpath before the jar file.