-
Suggestion
-
Resolution: Fixed
Dear Confluence team
As part of preparing our apps to the new XStream changes planned to be introduced by Confluence 7.10, we are facing one issue while doing the marshalling/unmarshalling process using the XStreamManagerCompat component.
We're saving in Bandana an object containing a list of Label (com.atlassian.confluence.labels.Label). While doing toXml() directly with XStreamManagerCompat bandana we get this exception:
this:
String marshalledXml = xStreamManagerCompat.toXML(ourObjectContainingLabel);
causes this:
2020-12-09 10:48:01,241 ERROR [Caesium-1-1] [confluence.remotepublishing.macro.RemotePublishPageMacro] doExecute There was an error while publishing content2020-12-09 10:48:01,241 ERROR [Caesium-1-1] [confluence.remotepublishing.macro.RemotePublishPageMacro] doExecute There was an error while publishing contentcom.thoughtworks.xstream.converters.reflection.ObjectAccessException: Invalid final field com.atlassian.confluence.labels.Namespace.namespacePrefix at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.validateFieldAccess(PureJavaReflectionProvider.java:150) at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:105) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter.marshal(ReflectionConverter.java:44) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter$1.writeField(ReflectionConverter.java:78) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter$1.visit(ReflectionConverter.java:59) at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:114) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter.marshal(ReflectionConverter.java:44) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:68) at com.thoughtworks.xstream.converters.collections.CollectionConverter.marshal(CollectionConverter.java:47) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter$1.writeField(ReflectionConverter.java:78) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter$1.visit(ReflectionConverter.java:59) at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:114) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter.marshal(ReflectionConverter.java:44) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter$1.writeField(ReflectionConverter.java:78) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter$1.visit(ReflectionConverter.java:59) at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:114) at com.thoughtworks.xstream.converters.reflection.ReflectionConverter.marshal(ReflectionConverter.java:44) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:68) at com.thoughtworks.xstream.converters.collections.CollectionConverter.marshal(CollectionConverter.java:47) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:68) at com.thoughtworks.xstream.converters.collections.MapConverter.marshal(MapConverter.java:51) at com.thoughtworks.xstream.core.ReferenceByXPathMarshaller.convertAnother(ReferenceByXPathMarshaller.java:36) at com.thoughtworks.xstream.core.TreeMarshaller.start(TreeMarshaller.java:46) at com.thoughtworks.xstream.core.ReferenceByXPathMarshallingStrategy.marshal(ReferenceByXPathMarshallingStrategy.java:17) at com.thoughtworks.xstream.XStream.marshal(XStream.java:489) at com.thoughtworks.xstream.XStream.marshal(XStream.java:479) at com.thoughtworks.xstream.XStream.toXML(XStream.java:464) at com.atlassian.confluence.compat.setup.xstream.XStream111Compat.toXML(XStream111Compat.java:20) at com.atlassian.confluence.compat.setup.xstream.XStreamManagerCompat.toXML(XStreamManagerCompat.java:50) at com.comalatech.confluence.remotepublishing.confluence.BandanaPublishHistoryManager.saveBandanaPublishHistoryInfoSpaceConfigs(BandanaPublishHistoryManager.java:76)
As you can see, the problem is related while the library handles the final attribute Namespace of the Label. The error is the same if we don't call to the XStreamManagerCompat and instead we rely in the XML marshalling of BandanaManager{{.}}
Previous to this, we're using directly a XStream instance defining the StaxDriver and a custom converter to be able to get rid of this exception and marshall/unmarshall the label object correctly. Code sample:
XStream xStream = new XStream(new StaxDriver()); // We were having problems with Label's Namespace, as it has a private constructor, so we need to convert from object to // XML and from XML to object manually xStream.registerConverter(new Converter() { @Override public boolean canConvert(Class aClass) { return aClass.equals(Namespace.class); } @Override public void marshal(Object o, HierarchicalStreamWriter hierarchicalStreamWriter, MarshallingContext marshallingContext) { Namespace namespace = (Namespace)o; hierarchicalStreamWriter.startNode("namespacePrefix"); hierarchicalStreamWriter.setValue(namespace.getPrefix()); hierarchicalStreamWriter.endNode(); } @Override public Object unmarshal(HierarchicalStreamReader hierarchicalStreamReader, UnmarshallingContext unmarshallingContext) { hierarchicalStreamReader.moveDown(); String namespacePrefix = hierarchicalStreamReader.getValue(); hierarchicalStreamReader.moveUp(); if (namespacePrefix.equals("my")){ return Namespace.PERSONAL; }else if (namespacePrefix.equals("team")){ return Namespace.TEAM; }else if (namespacePrefix.equals("global")){ return Namespace.GLOBAL; }else { return Namespace.SYSTEM; } } });
So we're kind of stuck here if from Confluence 7.10 we cannot add this kind of custom converters or configurations using the XStreamManagerCompat.
- Are you plan to resolve this adding some way to customize the internal XStream?
- Or in this case as the error is related to your internal Label model, maybe you can provide XStreamManagerCompat implementation already being compatible to marshall/unmarshall Confluence model.
Let us know if you need anything more.