How to clean install confluence plugin? Exception when loading bandana, cant cast classA to classA

Hello everyone, having some problems when getting values from bandana.

This is the code

ClassA classA = (ClassA) bandanaManager.getValue(context, id);

And this is the exeption

class org.example.plugin.classA cannot be cast to class org.example.plugin.classA (org.example.plugin.classA is in unnamed module of loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @abc; org.example.plugin.classA is in unnamed module of loader org.apache.felix.framework.BundleWiringImpl$BundleClassLoader @zxy)
public class Class A {
    String Name;
}

This is the example basically, the “Class A” was never changed, after upgrading this plugin from version 2 to 3 this exception started happening, the funny thing is that only some visual styles were changed and then this happened.

I believe this problem can be fixed by doing a clean install, however I have no idea how to do a clean install of our plugin, I’m confident that if the Confluence instance cleaned up the plugin would work fine, that’s impossible to do in our scenario though.

How can we fix this? How can we have a clean slate for our plugin? How can we do a clean install of our plugin?

PD: we haven’t been able to replicate this issue in our local environment, so have no idea how this exactly happened.

Thanks in advance

Dear @JohnReese

I’m afraid a clean install won’t help here - unless you want to drop the value stored in Bandana. Most app developers who are storing Objects in Bandana sooner or later have the same issue. The problem is within Confluence and how it handles class loading. It can happen that one classloaders stores the property which is later loaded with another classloader and then you have your conflict.

The only thing you can do is accessing your data (here name) without converting it to A. In one of our apps Tree View we have e.g. the following code:

	public TreeViewConfiguration getTreeViewConfigurationFromObject(Object o) {
		if(o == null) { return null; }
		TreeViewConfiguration conf = new TreeViewConfiguration();
		conf.setConditionalWatch((boolean) getFieldValue(o, "conditional_watch"));
		conf.setAddedMailHeader((String) getFieldValue(o, "added_mail_header"));
		conf.setAddedMailBody((String) getFieldValue(o, "added_mail_body"));
		conf.setMovedOutMailHeader((String) getFieldValue(o, "movedout_mail_header"));
		conf.setMovedOutMailBody((String) getFieldValue(o, "movedout_mail_body"));
		return conf;
	}
	
	
	private Object getFieldValue(Object o, String fieldName) {
		try  {
			Field f = o.getClass().getDeclaredField(fieldName);
			f.setAccessible(true);
			return f.get(o);
		}
		catch(Exception e) {
			return null;
		}
	}

Object o is the Object we get from Bandana.

I hope that helps.

Andreas