XStream double underscores and character escaping - java

I'm using XStream 1.4.9 to create XML from POJO classes. By default XStream escapes special characters like '>', '<' etc. Additionally it doubles underscore characters in element and attribute names. I need to disable this behaviour.
I was able to get rid of double underscores basing on this solution:
XStream and underscores
Disabling character escaping works with this solution:
How can I disable unnecessary escaping in XStream?
But I'm struggling with combining these approaches to achieve both goals in the same time.
I created custom Writer class ommiting character escaping:
public class NoEscapeWriter extends PrettyPrintWriter {
public NoEscapeWriter(Writer writer) {
super(writer);
}
#Override
protected void writeText(QuickWriter writer, String text) {
writer.write(text);
}
}
I implemented class extending DomDriver overriding createWriter() method and injecting XmlFriendlyNameCoder to its super class:
public class CustomDriver extends DomDriver {
public CustomDriver() {
super("UTF-8", new XmlFriendlyNameCoder("_-", "_"));
}
#Override
public HierarchicalStreamWriter createWriter(Writer out) {
return new NoEscapeWriter(out);
}
}
And I'm generating XML with XStream like this:
XStream xStream = new XStream(new CustomDriver());
xStream.processAnnotations(RootElement.class);
final String s = xStream.toXML(root);
Although it ommits character escaping as expected, it still generates output with double underscores like this:
<ROOT>
<TEST__ID><![CDATA[]]></TEST__ID>
<MULTIPLE__PART__NAME><![CDATA[]]></MULTIPLE__PART__NAME>
</ROOT>
I tried to extend DomDriver to inject XmlFriendlyNameCoder("-", "") to ommit double underscore problem and overriding createWriter() method to disable character escaping

Related

How to ignore some tags in XML in Jaxb

my xml file is below:
<ExternalCases>
<ignoreTag>
<CashLess>
<caseType>CashLess</caseType>
<claimNo>9</claimNo>
<status>Open</status>
</CashLess>
</ignoreTag>
</ExternalCases>
i want to ignore <ignoreTag> and i want <CashLess> tag in my Unmarshaller process.
my class like below:
#XmlRootElement(name="ExternalCases")
public class ExternalCases {
List<CashLess> cashLess;
#XmlElement(name="CashLess", required=false)
public List<CashLess> getCashLess() {
return cashLess;
}
public void setCashLess(List<CashLess> cashLess) {
this.cashLess = cashLess;
}
}
Thanks.
Ignoring ignoreTag
You could create a StAX filtered XMLStreamReader and have JAXB unmarshal that to ignore one or more XML elements.
http://docs.oracle.com/javase/7/docs/api/javax/xml/stream/XMLInputFactory.html#createFilteredReader%28javax.xml.stream.XMLStreamReader,%20javax.xml.stream.StreamFilter%29
Below is a link to a full example I gave in an answer to a similar question:
JAXB filtered parsing
If ignoreTag is a Grouping Element
If instead ignoreTag is a grouping element for the collection then you could map it as:
#XmlElementWrapper(name="ignoreTag")
#XmlElement(name="CashLess", required=false)
public List<CashLess> getCashLess() {
return cashLess;
Use answers of these questions::
JAXB ignoring xml tag attribute
JAXB - Ignore element
might be helpful!!!

How do I wrap a section of xml in a CDATA tag using Jackson

I have the following java object
class MyXmlObject{
#JsonProperty
private InnerObject innerObject;
#JsonProperty
private String someOtherProperty;
}
When I serialize this using
public String getXmlObjectAsXML(MyXmlObject myXmlObject){
JacksonXmlModule module = new JacksonXmlModule();
module.setDefaultUseWrapper(false);
XmlMapper mapper = new XmlMapper(module);
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);
String response = "";
response = mapper.writeValueAsString(myXmlObject);
return response;
}
I would like the InnerObject class to be wrapped in a CDATA tag.
What is the correct way to handle this scenario?
There is #JacksonXmlCData since 2.5. https://github.com/FasterXML/jackson-dataformat-xml:
#JacksonXmlCData allows specifying that the value of a property is to be serialized within a CData tag.
We had a similar use case. We needed all text fields in our XML wrapped in CDATA. It was a requirement of an API we needed to implement and we had no say in the API.
To solve the problem we created an implementation of #StaxMan's suggestion to override XMLOutputFactory and XMLStreamWriter to hijack writeCharacters() and call writeCData() instead, and this seems to work great. You can see a Gist of our exact code (with package names changed) here:
https://gist.github.com/jbcpollak/8312151
In brief, we created a CDataXmlOutputFactoryImpl class which creates a CDataXmlStreamWriter. Unfortunately, rather than using inheritance we needed to wrap the target classes because both were final. Also, the exact writer to use is variable, so wrapping is a safer option.
In the factory, in addition to wrapping all the other methods with pure pass-through functions, you'll need something like this for each createXMLStreamWriter() function (there are 4):
public XMLStreamWriter createXMLStreamWriter(Writer w)
throws XMLStreamException
{
return new CDataXmlStreamWriter(f.createXMLStreamWriter(w));
}
where f is an OutputFactoryImpl constructed in the class.
In CDataXmlStreamWriter all the necessary functions are pure delegates for the methods in w, except for the two methods below:
public void writeCharacters(char[] text, int start, int len)
throws XMLStreamException
{
w.writeCharacters(text, start, len);
}
// All this code just to override this method
public void writeCharacters(String text) throws XMLStreamException
{
w.writeCData(text);
}
Thats about all you need to do. Just use your new factory like this:
public void init() {
XmlFactory factory = new XmlFactory(new InputFactoryImpl(),
new CDataXmlOutputFactoryImpl());
xmlMapper = new XmlMapper(factory);
xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
}
The complete code can be see in the Gist above.
I'm not sure this solution would work if you only needed a few fields wrapped in CDATA. For that I think you would need to modify ToXmlGenerator, to make it aware of your model somehow (using annotations perhaps?) and then the generator would call writeCData() where necessary.
I am not aware of any option to make output use CDATA sections.
But why should you need to use CDATA sections? In XML CDATA is not semantically different from regular text section. It only exists as convenience thing for manual editing.
I ended up just putting in a placeholder, marshelling both objects, then manipulated the strings by hand... not clean not pretty but it worked.

How to parse a method or any other valid expression using JavaParser

JavaParser is a java source code parsing tool. I read the documents but found it only able to parse source of a full java class, like:
public class X {
public void show(String id) {
Question q = Quesiton.findById(id);
aaa.BBB.render(q);
}
}
But I want to parse only part of it, e.g. the method declaration:
public void show(String id) {
Question q = Quesiton.findById(id);
aaa.BBB.render(q);
}
How to do it or is it possible? If not, is there any other tool can do this?
Update
Actually I want to parse any valid expression in java, so I can do this easily with JavaParser:
CompilationUnit unit = JavaParser.parse(codeInputStream);
addField(unit, parseField("public String name")); // not possible now
I see you can include the method in a dummy class and parse it as usual. For the example you provided, enclose it inside:
public class DUMMY_CLASS_FOO {
// The string you're trying to parse (method or whatever)
}
Then you parse it as usual and neglect your dummy class while parsing.
UPDATE:
For the update you provided, you may try and catch
If the previous enclosure didn't do it, so enclose it into:
public class DUMMY_CLASS_FOO {
public void DUMMY_METHOD_FOO {
// Anything here
}
}
You might also search for Access Level Modifiers (public, private, ...etc), and if found, do the 1st solution. If not found, do the other one.

Jackson not naming fields how I want [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Different names of JSON property during serialization and deserialization
I am using Jackson on my site to create an options string to be used with a charting tool that expects JSON. So for example, I have a
public class Chart {
Integer zIndex = 3;
public Integer getZIndex() {
return zIndex;
}
}
so then I use Jackson's objectMapper on my chart and the output is {"zindex":3} where my issue is that the charting tool will not accept "zindex" but insists on the camel cased "zIndex".
What can I do to get this to be named properly in the output?
I've tried #JsonProperty("zIndex") but this generates two copies in the output, zindex and zIndex, which is confusing and ugly. Also, I am using lombok to generate my getters, if that makes a difference.
I tried:
public class FieldNamingStrategy extends PropertyNamingStrategy {
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
return field.getName();
}
}
and then
objectMapper.setPropertyNamingStrategy()
but this didn't work.
My configuration looks like
String json = null;
StringWriter stringWriter = new StringWriter();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
//TODO: figure this out
objectMapper.setPropertyNamingStrategy(new FieldNamingStrategy());
try {
final JsonGenerator jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(stringWriter);
jsonGenerator.useDefaultPrettyPrinter();
objectMapper.writeValue(jsonGenerator, object);
json = stringWriter.toString();
Make sure you use a modern version of Jackson: 1.9 improved handling of properties, so that annotation would work even when added to just one of pieces.
Or if you can not do that, just add #JsonProperty annotation to BOTH getter and field.
Your main problem is really that name itself is "non-compliant", meaning that pieces might not match.

Java XStream - Ignore tag that doesn't exist in XML

I currently use a piece of XML like the following
<Person>
<Name>Frank Smith</Name>
<Id>100023412</Id>
<DOB>12/05/1954</DOB>
<LasLogin>01/09/2010</LasLogin>
<FavOS>Windows</FavOS> // Wild card that may occasionally appear
</Person>
What I am stuck with, is when using XStream I need to be able to ignore certain tags that appear (in the case above 'FavOS')
These tags may not be known or change in the future. Is there a way to Ignore all tags that do not match what is currently implemented?
(Using XStream 1.3.1)
As it took me more than 15 minutes to find this answer, I thought I would post it.
XStream xstream = new XStream(new DomDriver()) {
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
public boolean shouldSerializeMember(Class definedIn, String fieldName) {
try {
return definedIn != Object.class || realClass(fieldName) != null;
} catch(CannotResolveClassException cnrce) {
return false;
}
}
};
}
};
This seems to skip xml items that are not in your objects.
XStream 1.4.5 supports dealing with tags which are not implemented. Use ignoreUnknownElements for tags which are not implemented yet or has been removed and you are dealing with old xml. You can also specify which particular tag you would like to ignore.
First of all, thanks for sharing this answer. It was very useful. However, the code mentioned above has issues. It does not have #Override annotations, which are a must to use this piece of code. Here is the updated code that works:
XStream xstream = new XStream(new StaxDriver()) {
#Override
protected MapperWrapper wrapMapper(MapperWrapper next) {
return new MapperWrapper(next) {
#Override
public boolean shouldSerializeMember(Class definedIn,
String fieldName) {
if (definedIn == Object.class) {
return false;
}
return super.shouldSerializeMember(definedIn, fieldName);
}
};
}
};
From the x-stream FAQ:
How does XStream deal with newer
versions of classes?
If a new field is added to the class, deserializing an old version
will leave the field uninitialized.
If a field is removed from the class, deserializing an old version that contains the field will cause an exception. Leaving the field in place but declaring it as transient will avoid the exception, but XStream will not try to deserialize it.
...
implement a custom mapper to ignore unknown fields automatically (see acceptance test CustomMapperTest.testCanBeUsedToOmitUnexpectedElements())
Since XStream 1.4.5 durring marshaller declaration it's enough to use ignoreEnknownElements() method:
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.getXStream().ignoreUnknownElements();
...
to ignore unnecessary elements.
I asked for exactly the same problem.
How can I make a XStreamMarshaller skip unknown binding?
And I got a comment linking this post.
I solved the my problem by extending the XStreamMarshaller.
public class ExtendedXStreamMarshaller extends XStreamMarshaller {
#Override
protected void configureXStream(final XStream xstream) {
super.configureXStream(xstream);
xstream.ignoreUnknownElements(); // will it blend?
}
}

Categories