I'll describe how this is done when using the built-in Sun implementation by an example.
Suppose this is my JAXB annotated class:
package org.oded; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.*; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Item { @XmlAttribute public int id; public String text; }
Next I run the Main class:
package org.oded;
import java.io.*;
import javax.xml.bind.*;
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
public class Main
{
public static void main( String[] args ) throws Exception
{
Item i1 = new Item();
i1.text = "hello";
i1.id = 1;
Item i2 = new Item();
i2.text = "
";
i2.id = 2;
Marshaller m = JAXBContext.newInstance( Item.class ).createMarshaller();
m.marshal( i1, new OutputStreamWriter( System.out ) );
System.out.println();
m.marshal( i2, new OutputStreamWriter( System.out ) );
}
}
The output is:
hello <code><helloWorld/></code>
Now suppose I want to wrap the XML value of text in a CDATA element and avoid the escaping, I need to add specify an Adapter for text to surround the value in a CDATA element in the following way:
package org.oded; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.*; @XmlRootElement @XmlAccessorType(XmlAccessType.FIELD) public class Item { @XmlAttribute public int id; @XmlJavaTypeAdapter(value=Adapter.class) public String text; private static class Adapter extends XmlAdapter{ @Override public String marshal( String v ) throws Exception { return "<![CDATA[" + v + "]]>"; } @Override public String unmarshal( String v ) throws Exception { return v; } } }
Now tell the Marshaller, in a Sun-specific way, not to escape the value of text:
package org.oded;
import java.io.*;
import javax.xml.bind.*;
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
public class Main
{
public static void main( String[] args ) throws Exception
{
Item i1 = new Item();
i1.text = "hello";
i1.id = 1;
Item i2 = new Item();
i2.text = "
";
i2.id = 2;
Marshaller m = JAXBContext.newInstance( Item.class ).createMarshaller();
m.setProperty( "com.sun.xml.internal.bind.characterEscapeHandler", new CharacterEscapeHandler() {
@Override
public void escape( char[] ac, int i, int j, boolean flag, Writer writer ) throws IOException
{
// do not escape
writer.write( ac, i, j );
}
});
m.marshal( i1, new OutputStreamWriter( System.out ) );
System.out.println();
m.marshal( i2, new OutputStreamWriter( System.out ) );
}
}
Now the output is:
<![CDATA[hello]]> <![CDATA[ ]]>
This post helped me a lot.
ReplyDeleteVery nice. Clean.
ReplyDeletethanks... easy to understand... i implemented the above and got the below exception:
ReplyDeletejavax.xml.bind.PropertyException: name: com.sun.xml.internal.bind.marshaller.characterEscapeHandler value: test.ObjectToXML$1@44118bb
please can you advise what could be the problem?
found this post that with the same problem...:
http://metro.1045641.n5.nabble.com/Implementing-CharacterEscapeHandler-using-JDK6-td1063492.html
I looked at the source of the exception (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/com/sun/xml/internal/bind/v2/runtime/MarshallerImpl.java) and it seems that your class "test.ObjectToXML" does not implement "com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler"
ReplyDeletetry using
ReplyDeletem.setProperty( CharacterEscapeHandler.class.getName(), new CharacterEscapeHandler() {
public void escape(char[] ac, int i, int j, boolean flag,
Writer writer) throws IOException {
// TODO Auto-generated method stub
writer.write( ac, i, j );
}
});
Nice post. But could not find out jar contains class you used:
ReplyDeletecom.sun.xml.internal.bind.marshaller.CharacterEscapeHandler
Also, the compiler complains about:
private static class Adapter extends XmlAdapter
Should it be like below?
private static class Adapter extends XmlAdapter
Very useful thank you very much.
ReplyDeleteAbout the errors above with the CharacterEscapeHandler, plase have a look here: http://stackoverflow.com/questions/860187/access-restriction-on-class-due-to-restriction-on-required-library-rt-jar
Unfortunately, your example is broken: Your adapter does not handle CDATA end tags ]]> properly. This breaks the generated XML if that string is contained in the input.
ReplyDeleteMore severely, the CharacterEscapeHandler instance turns off escaping completely for all tags. As a consequence you _must_ use CDATA tags for all members that might contain special charactes like (greater than).
Unfortunately, there there seems to be no feasible way to conveniently use escaping for some tags and CDATA for others with your approach.
Thanks, great post. Really usefull!
ReplyDeleteThank you a lot, actually I have found this post is very useful. Your solution is the shortest and clearest then other solutions, which I have ever seen before.
ReplyDeleteI am continually amazed by the amount of information available on this subject. What you presented was well researched and well worded in order to get your stand on this across to all your readers. marsbahis giriş
ReplyDeleteCool and that i have a super offer you: Who Does Renovations home renovation quotes
ReplyDeleteCool and I have a keen offer you: Where To Start With Whole House Renovation whole home remodel
ReplyDeleteRespect and that i have a swell offer you: How Much House Renovation Cost Philippines house renovation exterior
ReplyDelete