Hi,
I'm afraid we can't provide a more convince DSL to set the xstream
instance. Because the unmarshal().xstream() is defined in camel-core and
we don't want to introduce the dependency of the XStream to camel-core.
For you case I think you can create a XStreamDataFormat instance
globally in route for marshal and unmarshal like this
public void configure() {
XStream xstream = new XStream();
xstream.registerConverter(new XmlEncodedStringConverter());
DataFormat xstreamDataFormat = new XStreamDataFormat(xstream);
from("direct:start")
.unmarshal(xstreamDataFormat)
.process(myProcessor)
.marshal(xstreamDataFormat)
.convertBodyTo(String.class)
.to("mock:result");
}
If you want to share the XStreamDataFormat in the whole camelContext,
you may need to register this DataFormat into the JndiRegistry and
introduce a ref() DSL to get this reference from the registry.
BTW, you also need to make sure the XStreamDataFormat is thread safe.
Willem
jonathanq wrote:
I managed to work around the issue by using a Custom Converter in XStream.
I created an XmlEncodedStringConverter that used the apache commons lang
StringEscapeUtils.escapeXml() and unescapeXml():
public class XmlEncodedStringConverter implements Converter {
public void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
String value = (String)source;
writer.setValue(StringEscapeUtils.escapeXml(value));
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
String escapedValue = reader.getValue();
return StringEscapeUtils.unescapeXml(escapedValue);
}
public boolean canConvert(Class type) {
return String.class.isAssignableFrom(type);
}
}
Then when I publish a message to my queues - I use Xstream like this:
XStream xstream = new XStream()
xstream.registerCustomConverter(new XmlEncodedStringConverter());
template.sendBody("direct:start", xstream.toXml(myObject));
In my Camel Routes - I did this:
public void configure() {
XStream xstream = new XStream();
xstream.registerConverter(new XmlEncodedStringConverter());
from("direct:start")
.unmarshal(new XStreamDataFormat(xstream))
.process(myProcessor)
.marshal(new XStreamDataFormat(xstream))
.convertBodyTo(String.class)
.to("mock:result");
}
Doing this - all of my issues/exceptions disappeared. Not ideal - but it
should work until the issue can be resolved in Camel 2.2.0 and we can
upgrade these processes to that version.
Is there an easier way of doing that? ie: Is there a way I can create the
xstream instance that the route will use so that i can do:
unmarshal().xstream() - and register the xstream instance globally for the
whole camel context? Or is this the only way to set the instance of xstream
used by the unmarshalling processor?
Thanks!
Jonathan
willem.jiang wrote:
It's a bug of XStream DataFormat.
I created a JIRA[1] for it.
[1] https://issues.apache.org/activemq/browse/CAMEL-2407
Willem
jonathanq wrote:
I should also mention - this is Camel 2.0.0
jonathanq wrote:
I am trying to unmarshal an xml message from JMS that was originally
marshaled using Xstream.
When I create the message I am doing this:
XStream xstream = new XStream(new DomDriver("ISO-8859-1"));
template.sendBody(xstream.toXml(myObject));
On the consuming process I have this in my route:
from(endpoint).unmarshal().xstream().process(myProcessor);
The XStream unmarshal always fails due to non-UTF-8 characters. And the
stacktrace shows that it was a UTF8 reader that failed.
So my question is - is there a way to initialize XStream to use a
specific
DomDriver (with an encoding). Or any way to specify the encoding to use
by default?
I tried adding this to the route (right after the from, and before the
unmarshal):
.setProperty(Exchange.CONTENT_ENCODING, constant("iso-8859-1"))
Didn't make a difference.
Here is the stack trace:
Caused by: com.thoughtworks.xstream.io.StreamException: : Invalid UTF-8
start byte 0xa0 (at char #638, byte #-1)
at
com.thoughtworks.xstream.io.xml.StaxReader.pullNextEvent(StaxReader.java:64)
at
com.thoughtworks.xstream.io.xml.AbstractPullReader.readRealEvent(AbstractPullReader.java:137)
at
com.thoughtworks.xstream.io.xml.AbstractPullReader.readEvent(AbstractPullReader.java:130)
at
com.thoughtworks.xstream.io.xml.AbstractPullReader.move(AbstractPullReader.java:109)
at
com.thoughtworks.xstream.io.xml.AbstractPullReader.moveDown(AbstractPullReader.java:94)
at
com.thoughtworks.xstream.io.xml.StaxReader.<init>(StaxReader.java:44)
at
com.thoughtworks.xstream.io.xml.StaxReader.<init>(StaxReader.java:34)
at
org.apache.camel.dataformat.xstream.XStreamDataFormat.createHierarchicalStreamReader(XStreamDataFormat.java:83)
at
org.apache.camel.dataformat.xstream.AbstractXStreamWrapper.unmarshal(AbstractXStreamWrapper.java:88)
at
org.apache.camel.processor.UnmarshalProcessor.process(UnmarshalProcessor.java:51)
at
org.apache.camel.management.InstrumentationProcessor.process(InstrumentationProcessor.java:61)
at
org.apache.camel.processor.RedeliveryErrorHandler.processExchange(RedeliveryErrorHandler.java:186)
at
org.apache.camel.processor.RedeliveryErrorHandler.processErrorHandler(RedeliveryErrorHandler.java:155)
at
org.apache.camel.processor.RedeliveryErrorHandler.process(RedeliveryErrorHandler.java:88)
at
org.apache.camel.processor.DefaultErrorHandler.process(DefaultErrorHandler.java:49)
at
org.apache.camel.processor.DefaultChannel.process(DefaultChannel.java:148)
at org.apache.camel.processor.Pipeline.process(Pipeline.java:74)
at
org.apache.camel.processor.UnitOfWorkProcessor.processNext(UnitOfWorkProcessor.java:54)
at
org.apache.camel.processor.DelegateProcessor.process(DelegateProcessor.java:48)
at
org.apache.camel.component.direct.DirectProducer.process(DirectProducer.java:45)
at
org.apache.camel.impl.ProducerCache$1.doInProducer(ProducerCache.java:170)
at
org.apache.camel.impl.ProducerCache$1.doInProducer(ProducerCache.java:156)
at
org.apache.camel.impl.ProducerCache.doInProducer(ProducerCache.java:141)
at
org.apache.camel.impl.ProducerCache.sendExchange(ProducerCache.java:155)
at org.apache.camel.impl.ProducerCache.send(ProducerCache.java:93)
at
org.apache.camel.impl.DefaultProducerTemplate.send(DefaultProducerTemplate.java:97)
at
org.apache.camel.impl.DefaultProducerTemplate.sendBodyAndHeader(DefaultProducerTemplate.java:136)
... 29 more
Caused by: com.ctc.wstx.exc.WstxIOException: Invalid UTF-8 start byte
0xa0
(at char #638, byte #-1)
at com.ctc.wstx.sr.StreamScanner.throwFromIOE(StreamScanner.java:708)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1086)
at
com.thoughtworks.xstream.io.xml.StaxReader.pullNextEvent(StaxReader.java:49)
... 55 more
Caused by: java.io.CharConversionException: Invalid UTF-8 start byte
0xa0
(at char #638, byte #-1)
at com.ctc.wstx.io.UTF8Reader.reportInvalidInitial(UTF8Reader.java:302)
at com.ctc.wstx.io.UTF8Reader.read(UTF8Reader.java:188)
at com.ctc.wstx.io.ReaderSource.readInto(ReaderSource.java:84)
at
com.ctc.wstx.io.BranchingReaderSource.readInto(BranchingReaderSource.java:57)
at com.ctc.wstx.sr.StreamScanner.loadMore(StreamScanner.java:992)
at com.ctc.wstx.sr.StreamScanner.getNext(StreamScanner.java:763)
at
com.ctc.wstx.sr.BasicStreamReader.nextFromProlog(BasicStreamReader.java:1995)
at com.ctc.wstx.sr.BasicStreamReader.next(BasicStreamReader.java:1069)