问题
I want to force escaping special characters when I use Spring Marshaller. Below code is perfectly working when I use javax.xml.bind.Marshaller
Book Class
package com.odr.core.action;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "book")
public class Book {
private String name;
private String author;
private String publisher;
private String isbn;
@XmlJavaTypeAdapter(value=CDATAAdapter.class)
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public String getPublisher() {
return publisher;
}
public void setPublisher(String publisher) {
this.publisher = publisher;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public String toString() {
return "Book [name=" + name + ", author=" + author + ", publisher="
+ publisher + ", isbn=" + isbn + ", description=" + description
+ "]";
}
}
Object to XML
writer = new BufferedWriter(new FileWriter(selectedFile));
context = JAXBContext.newInstance(Book.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.setProperty("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
new CharacterEscapeHandler() {
@Override
public void escape(char[] ch, int start, int length,
boolean isAttVal, Writer writer)
throws IOException {
writer.write(ch, start, length);
}
});
m.marshal(book, writer);
Output:
<description>
<![CDATA[<p>With hundreds of practice questions and hands-on exercises, <b>SCJP Sun Certified Programmer for Java 6 Study Guide</b> covers what you need to know--and shows you how to prepare--for this challenging exam. </p>]]>
</description>
But same kind of code is not working when I use org.springframework.oxm.jaxb.Jaxb2Marshaller, Below is the code
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
Map<String, Object> map = new HashMap<String, Object>();
map.put("jaxb.formatted.output", true);
jaxb2Marshaller.setPackagesToScan("com.odr.core.action");
// com.sun.xml.bind.characterEscapeHandler
// com.sun.xml.bind.marshaller.CharacterEscapeHandler
map.put("com.sun.xml.bind.marshaller.CharacterEscapeHandler",
new CharacterEscapeHandler() {
@Override
public void escape(char[] ac, int i, int j, boolean flag,
Writer writer) throws IOException {
writer.write(ac, i, j);
}
});
jaxb2Marshaller.setMarshallerProperties(map);
org.springframework.oxm.Marshaller marshaller = jaxb2Marshaller;
FileOutputStream fos = null;
// String fileNamePath = directory.getAbsolutePath() + "\\" + fileName;
try {
// fos = new FileOutputStream(fileNamePath);
fos = new FileOutputStream(selectedFile);
marshaller.marshal(book, new StreamResult(fos));
// File f = new File(directory,fileName);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
fos.close();
}
}
Output
<description><![CDATA[<p>With hundreds of practice questions and hands-on exercises, <b>SCJP Sun Certified Programmer for Java 6 Study Guide</b> covers what you need to know--and shows you how to prepare--for this challenging exam. </p>]]></description>
The first snippet didn't encode the special characters. But the second snippet which is using Spring did encode though I set property. I have to use Spring in my project for not affecting existing code. Is there any way I can fix it
回答1:
Ok, I had the same problem, and I solved it this way.
First things first. You should create two beans. One for the Jaxb2Marshaller
and another MarshallingHttpMessageConverter
. I'm supposing that you want to keep your configuration, so I'm going to use your code.
Creating the Jaxb2Marshaller
bean:
@Bean
public Jaxb2Marshaller getJaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
Map<String, Object> map = new HashMap<String, Object>();
map.put("jaxb.formatted.output", true);
jaxb2Marshaller.setPackagesToScan("com.odr.core.action");
map.put("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
new CharacterEscapeHandler() {
@Override
public void escape(char[] ac, int i, int j, boolean flag,
Writer writer) throws IOException {
writer.write(ac, i, j);
}
});
jaxb2Marshaller.setMarshallerProperties(map);
org.springframework.oxm.Marshaller marshaller = jaxb2Marshaller;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(selectedFile);
marshaller.marshal(book, new StreamResult(fos));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
fos.close();
}
}
return jaxb2Marshaller;
}
Well, I'm using Java 8 so I changed com.sun.xml.bind.marshaller.CharacterEscapeHandler to com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler as you can see above.
Creating the MarshallingHttpMessageConverter
bean:
@Bean
public MarshallingHttpMessageConverter getMarshallingHttpMessageConverter() {
return new MarshallingHttpMessageConverter(getJaxb2Marshaller());
}
You must notice that I've created my own HttpMessageConverter to solve the problem. That's because Spring uses it's own converter that creates a new Marshaller
instance everytime it needs to convert a entity or a DTO to XML objetct. So, I think the code below will solve your problem. Hope it helps you.
import com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.xml.MarshallingHttpMessageConverter;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
@Configuration
public class XmlParseConfig {
@Bean
public Jaxb2Marshaller getJaxb2Marshaller() {
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
Map<String, Object> map = new HashMap<String, Object>();
map.put("jaxb.formatted.output", true);
jaxb2Marshaller.setPackagesToScan("com.odr.core.action");
map.put("com.sun.xml.internal.bind.marshaller.CharacterEscapeHandler",
new CharacterEscapeHandler() {
@Override
public void escape(char[] ac, int i, int j, boolean flag,
Writer writer) throws IOException {
writer.write(ac, i, j);
}
});
jaxb2Marshaller.setMarshallerProperties(map);
org.springframework.oxm.Marshaller marshaller = jaxb2Marshaller;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(selectedFile);
marshaller.marshal(book, new StreamResult(fos));
} catch (Exception e) {
e.printStackTrace();
} finally {
if (fos != null) {
fos.close();
}
}
return jaxb2Marshaller;
}
@Bean
public MarshallingHttpMessageConverter getMarshallingHttpMessageConverter() {
return new MarshallingHttpMessageConverter(getJaxb2Marshaller());
}
}
来源:https://stackoverflow.com/questions/38381951/force-escaping-special-character-in-xml-marshalling-in-spring