XMLRootElement converting a class to XML in jersey - java

I'm very good in converting a model class to JSON Array or Object.
But i'm a noob when it comes to XML.
I want my final output to be like this
<Response>
<Say voice="alice">Thanks for trying our documentation. Enjoy!</Say>
</Response>
To achieve it i create a model class
#XmlRootElement(name = "Response")
public class Response {
private Say say = new Say();
public Say getSay() {
return say;
}
public void setSay(Say say) {
this.say = say;
}
#XmlRootElement(name = "Say")
static class Say {
#XmlAttribute
private String voice = "alice";
private String string = "Thanks for trying our documentation. Enjoy!";
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
}
Now after converting it to XML with jersey my output was
<Response>
<say voice="alice">
<string>Thanks for trying our documentation. Enjoy!</string>
</say>
</Response>
I got a extra string tag. I'm not sure what attribute to set for the String so that it comes in the body.? Or is there any other way?
Also for say. The 'S' is not capitalised. How can i make it a capital letter?
Thanks in advance

By default properties and public fields will be mapped to elements. What you want to do is use #XmlValue to map the field to the element's value.
#XmlRootElement(name = "Say")
#XmlAccessorType(XmlAccessType.FIELD)
static class Say {
#XmlAttribute
private String voice = "alice";
#XmlValue
private String string = "Thanks for trying our documentation. Enjoy!";
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
Note the use of #XmlAccessorType(XmlAccessType.FIELD). This is so the default behavior doesn't "doubly" attempt to map the property defined by the getter and setter. Alternatively, you could place the annotations on the getter, and leave out the the #XmlAccessorType
Result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Response>
<say voice="alice">Thanks for trying our documentation. Enjoy!</say>
</Response>
public class ResponseTest {
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Response.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Response response = new Response();
marshaller.marshal(response, System.out);
}
}
UPDATE
but can i know why the 'S' in Say is not capitalised even though #XmlRootElement(name = "Say") is specified?
You need to specify the name with #XmlElement(name = "Say") on the property. If you don't the default naming will kick in.
#XmlElement(name = "Say")
public Say getSay() {
return say;
}
The XmlRootElement(name = "Say") is only for if the element is used as the root element. For instance this:
Response.Say response = new Response.Say();
marshaller.marshal(response, System.out);
Would give you this output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Say voice="alice">Thanks for trying our documentation. Enjoy!</Say>

Related

Android - SimpleXML framework cannot parse #ElementList

I am using SimpleXML framework to parse xmls in my Android application. I have a problem with getting #ElementList parsed correctly.
A fragment of xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SaleToPOIResponse>
<MessageHeader (...) />
<ReconciliationResponse ReconciliationType="SaleReconciliation">
<Response Result="Success"/>
<TransactionTotals PaymentInstrumentType="Card">
<PaymentTotals TransactionType="Debit" TransactionCount="182" TransactionAmount="4.17"/>
<PaymentTotals TransactionType="Credit" TransactionCount="1" TransactionAmount="2.01"/>
</TransactionTotals>
</ReconciliationResponse>
</SaleToPOIResponse>
My classes look:
ReconciliationResponseType.java:
#Root
#Order(elements = {
"Response",
"TransactionTotals"
})
public class ReconciliationResponseType {
#Element(name = "Response", required = true)
protected ResponseType response;
#ElementList(name = "TransactionTotals", inline = true, required = false)
protected List<TransactionTotalsType> transactionTotals;
#Attribute(name = "ReconciliationType", required = true)
protected String reconciliationType;
// getters and setters
}
TransactionTotalsType.java:
#Root
#Order(elements = {
"PaymentTotals",
"LoyaltyTotals"
})
public class TransactionTotalsType {
#ElementList(name = "PaymentTotals", inline = true, required = false)
protected List<PaymentTotalsType> paymentTotals;
#Attribute(name = "PaymentInstrumentType", required = true)
protected String paymentInstrumentType;
// getters and setters
}
I parse it using method:
public static SaleToPOIResponse fromXMLString(String xmlResponse) {
Reader reader = new StringReader(xmlResponse);
Serializer serializer = new Persister();
try {
SaleToPOIResponse response = serializer.read(SaleToPOIResponse.class, reader, false);
return response;
} catch (Exception e) {
Log.e(TAG, "Exception during parsing String XML to SaleToPOIResponse: ", e);
}
return null;
}
But every time I get an exception, that ordered element 'TransactionTotals' is missing, even though 1) it is not required 2) it does exist in the parsed xml
org.simpleframework.xml.core.ElementException: Ordered element 'TransactionTotals' missing for class pl.novelpay.epas.generated.saletopoimessages.ReconciliationResponseType
When I comment the 'TransactionTotals' from #Order the xml is parsed without an exception, but the TransactionTotals filed in result is empty. What am I missing here?
I found what was a problem while reading answer to a similar problem here:
https://sourceforge.net/p/simple/mailman/message/25699359/
I was using name insted of entry. So an ElementList attribute should look like this:
#ElementList(entry= "PaymentTotals", inline = true, required = false)
protected List<PaymentTotalsType> paymentTotals;
Now it works perfectly.

using one POJO class for different xml responses

When I call rest service I get different xml responses, with different xml root element. I would like to know, are there any opportunities to unmarshal these xmls to one pojo class.
For example, I have a class RecordingCreated.
#XmlRootElement(name = "recordingCreated")
public class RecordingCreated {
private String nodeID;
private String cameraID;
private String recPath;
private String recordingStatus;
public String getNodeID() {
return nodeID;
}
#XmlElement
public void setNodeID(String nodeID) {
this.nodeID = nodeID;
}
public String getCameraID() {
return cameraID;
}
#XmlElement
public void setCameraID(String cameraID) {
this.cameraID = cameraID;
}
public String getRecPath() {
return recPath;
}
#XmlElement
public void setRecPath(String recPath) {
this.recPath = recPath;
}
public String getRecordingStatus() {
return recordingStatus;
}
#XmlElement
public void setRecordingStatus(String recordingStatus) {
this.recordingStatus = recordingStatus;
}
}
After calling rest service I can get xml response in the form of
<recordingCreated>
<nodeID>"111</nodeID>
<cameraID>222</cameraID>\
<recordingID>333</recordingID>\
<recPath>rec</recPath>
<recordingStatus>recorded</recordingStatus>
</recordingCreated>
And in the form of
<error>
<code>444</code>
<description>broker: access denied</description>
</error>
When I got first xml resposne, JAXB unmarshal good
JAXBContext jaxbContext = JAXBContext.newInstance(RecordingCreated.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
RecordingCreated recordingCreated = (RecordingCreated) jaxbUnmarshaller.unmarshal(inputStream);
But when I got second response, of course, I got an error, like this
javax.xml.bind.UnmarshalException: unexpected element (uri:"",
local:"error"). Expected elements are <{}recordingCreated>]]
Question: Is there any opportunity having one class unmarshal two various xml responses with different root elements?
Try creating two different sub classes for your two different responses with their corresponding roots.
You can have the current class as posted as the parent for both of them and depending on the response you would get, call the required class.

Display XML correctly in Firefox with Jackson

I'm converting a JSON file into an ArrayList and then to XML by using Jackson. It is displayed in Firefox but just as a normal String. By using the inspect element tool I get the whole formatted xml though. Which function can I use to display it correctly on the browser?
My method:
private void init() throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
InputStream is = MyClass[].class.getResourceAsStream("/config/myList.json");
myList= Arrays.asList(mapper.readValue(is, MyClass[].class));
XmlMapper xmlMapper = new XmlMapper();
for(MyClass test : myList){
String asXml += xmlMapper.writeValueAsString(test);
}
LOGGER.info("asXml: {}.", asXml);
}
Desired output in browser:
<myclass xmlns="">
<myclass>XyClass</ci>
<myname>XyName</ci>
...
</myclass>
Actual output:
XyClassXyName...
Quite simplified the class looks like this:
#JacksonXmlRootElement(localName ="MyClass")
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class MyClass {
#XmlElement(required = true)
private String class;
#XmlElement(required = true)
private String name;
//....
//standard constructor
public MyClass() { }
public CI(String class, String name){
this.class = class;
this.name = name;
}
public String getClass() {
return class;
}
public String getName() {
return name;
}
public void setClass(String class) {
this.class = class;
}
public void setName(String name) {
this.name = name;
}
}
Another weird thing is that I have the exact annotations in another class, trying the same thing with that and there the browser does not display anything... Thanks for any help.
Well my mistake derived from two things basically. Most important is the definiton of the XML Root Element (not only as annotation in your "MyClass"). Define a global String to create a XML Root element, otherwise your document won't be well-formed and the mistake "junk after document element" will be shown.
private String asXml ="<?xml version=\"1.0\" encoding=\"utf-8\"?><MyList>";
I've adapted the method to:
private void init() throws JsonParseException, JsonMappingException, IOException {
ObjectMapper mapper = new ObjectMapper();
InputStream is = MyClass[].class.getResourceAsStream("/config/myList.json");
myList= Arrays.asList(mapper.readValue(is, MyClass[].class));
XmlMapper xmlMapper = new XmlMapper();
for(MyClass test : myList){
String asXml += xmlMapper.writer().with(SerializationFeature.WRAP_ROOT_VALUE).withRootName("MyClass").writeValueAsString(test);
}
LOGGER.info("asXml: {}.", asXml);
asXml += "</MyList>";
}
And don't forget to add the correct MediaType in your RestController:
#RequestMapping(value="/display", method=RequestMethod.GET, produces=MediaType.APPLICATION_XML_VALUE)
public #ResponseBody String getList(Model model) {
return service.getAsXmlString();
}

JAXB unmarshal returning null values

I am using JAXB to convert XML file to java object
I have looked a lot in the examples on the web but still get null values in my object when I unmarshall it to a java object
what I miss?
File file = new File("BootloaderProtocol.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Command.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Command commanda = (Command) jaxbUnmarshaller.unmarshal(file);
System.out.println(commanda);
my class:
#XmlRootElement(name="Command")
public class Command {
String COMMAND_ID;
String COMMAND_NAME;
String COMMAND_CODES;
public String getCOMMAND_ID() {
return COMMAND_ID;
}
#XmlElement
public void setCOMMAND_ID(String COMMAND_ID) {
this.COMMAND_ID = COMMAND_ID;
}
public String getCOMMAND_NAME() {
return COMMAND_NAME;
}
#XmlElement
public void setCOMMAND_NAME(String COMMAND_NAME) {
this.COMMAND_NAME = COMMAND_NAME;
}
public String getCOMMAND_CODES() {
return COMMAND_CODES;
}
#XmlElement
public void setCOMMAND_CODES(String COMMAND_CODES) {
this.COMMAND_CODES = COMMAND_CODES;
}
}
and this my XML file:
<Command>
<COMMAND>
<COMMAND_ID>0xFE01</COMMAND_ID>
<COMMAND_NAME>Start bootloader</COMMAND_NAME>
<COMMAND_CODES>EE120301FE0900</COMMAND_CODES>
</COMMAND>
</Command>
This is the correct xml structure:
<Command>
<COMMAND_ID>0xFE01</COMMAND_ID>
<COMMAND_NAME>Start bootloader</COMMAND_NAME>
<COMMAND_CODES>EE120301FE0900</COMMAND_CODES>
</Command>
Try your code with this xml. Use the correct path of the xml file in the code.
Btw, I have tested your code with this xml and it works fine.
try something like this
public class Command {
#XmlElement(name="COMMAND")
public NestedCommand command;
static class NestedCommand {
String COMMAND_ID;

JAXB null instead empty string during marshaling

How I can print 'null' as field value, when marshalling the string?
Example: error and error_code are Strings, and i want to use 'null' as a value indicating that there is no value/errors happened on the server side.
{
"error_code": null,
"error": null
}
Today, I have to use EMPTY values, so that "error_code" or "error" these fields generally fall into json, and if they were not explicitly initialized as this.errorCode = StringUtils.EMPTY;
So today, I have next json:
{
"error_code": "",
"error": ""
}
This is how that looks in a code:
#XmlRootElement()
#XmlAccessorType(XmlAccessType.FIELD)
public class Response
{
#SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(Response.class);
public static final String ERROR_FIELD_NAME = "error";
public static final String ERROR_CODE_FIELD_NAME = "error_code";
// #XmlJavaTypeAdapter(CafsResponse.EmptyStringAdapter.class)
#XmlElement(name = Response.ERROR_CODE_FIELD_NAME)
private String errorCode;
// #XmlJavaTypeAdapter(CafsResponse.EmptyStringAdapter.class)
#XmlElement(name = Response.ERROR_FIELD_NAME)
private String errorMessage;
// Empty Constructor
public Response()
{
this.errorCode = StringUtils.EMPTY; // explicit initialization, otherwise error_code will not appear as part of json, how to fix this this ?
this.errorMessage = StringUtils.EMPTY;
}
etc...
// Empty Constructor
public Response()
{
this.errorCode = null; // this variant dosn't work either, and error_code again didn't get to json
this.errorMessage = null;
}
See, #XmlJavaTypeAdapter, i thought that this potentially could help me - but no :)
Instead of null value, i'm getting "null" as string.
if (StringUtils.isEmpty(str))
{
return null;
}
return str;
{
"error_code": "null", // this is not whta i wanted to get.
"error": "null"
}
Any help on this? - ask me if something is not clear.
full list:
/**
* Empty string Adapter specifying how we want to represent empty strings
* (if string is empty - treat it as null during marhsaling)
*
*/
#SuppressWarnings("unused")
private static class EmptyStringAdapter extends XmlAdapter<String, String>
{
#Override
public String unmarshal(String str) throws Exception
{
return str;
}
#Override
public String marshal(String str) throws Exception
{
if (StringUtils.isEmpty(str))
{
return null;
}
return str;
}
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
You could use MOXy as your JSON provider to support this use case. Below is an example:
Response
MOXy will marshal properties marked with #XmlElement(nillable=true) to the representation you are looking for
(see: http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html).
package forum11319741;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
public static final String ERROR_FIELD_NAME = "error";
public static final String ERROR_CODE_FIELD_NAME = "error_code";
#XmlElement(name = Response.ERROR_CODE_FIELD_NAME, nillable = true)
private String errorCode;
#XmlElement(name = Response.ERROR_FIELD_NAME, nillable = true)
private String errorMessage;
}
jaxb.properties
To use MOXy as your JAXB provider you need to include a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package forum11319741;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Response.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("eclipselink.media-type", "application/json");
marshaller.setProperty("eclipselink.json.include-root", false);
Response response = new Response();
marshaller.marshal(response, System.out);
}
}
Output
{
"error_code" : null,
"error" : null
}
MOXy and JAX-RS
You can use the MOXyJsonProvider class to enable MOXy as your JSON provider in your JAX-RS application (see: http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html).
package org.example;
import java.util.*;
import javax.ws.rs.core.Application;
import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
public class CustomerApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
HashSet<Class<?>> set = new HashSet<Class<?>>(2);
set.add(MOXyJsonProvider.class);
set.add(CustomerService.class);
return set;
}
}
For More Information
http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html

Categories

Resources