I have a service that does the following:
receives different XML requests
turns them into JIBX-generated Java objects
maps the JIBX-generated Java objects into POJOs
sends the POJOs to another service
gets a POJO response back
maps POJO back into JIBX-generated Java objects
turns JIBX-generated Java objects back into XML
returns XML to client.
I'd like to make this process more efficient. Can anyone suggest how? Can JIBX map directly into my POJOs?
Yes Jibx can map directly to your POJOs using Jibx mapping files. I think the below link will be very helpful to understand Jibx binding.
Jibx Introduction
In this you needed library which is available in the url(4shared.com) commented in comments.
package com.xml.Sample.MainP;
import java.io.File;
import java.util.List;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import com.xml.Sample.Actions.XMLAction;
import com.xml.Sample.Model.States;
public class Retrieve {
public static String XMLModelName = "com.xml.Sample.Model.States";
private static String cities = "E:\\Webeclipseworkspace\\Samples\\src\\Srates.xml";
public static void main(String[] args) {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
File f = new File(cities);
Document doc = db.parse(f);
doc.getDocumentElement().normalize();
XMLAction xmla = new XMLAction();
List<States> listXML = xmla.readData(XMLModelName, doc);
// System.out.println(listXML);
String xmlData = xmla.writtingData(listXML);
System.out.println(xmlData);
} catch (Exception e) {
// TODO: handle exception
System.out.println(e);
}
}
}
package com.xml.Sample.Model;
import com.xml.Sample.XMLAnn.XMLColumn;
import com.xml.Sample.XMLAnn.XMLReport;
#XMLReport(reportName = "row")
public class Directory {
private String city_id;
private String city_name;
private String state_id;
#XMLColumn(label = "city_id")
public String getCity_id() {
return city_id;
}
public void setCity_id(String city_id) {
this.city_id = city_id;
}
#XMLColumn(label = "city_name")
public String getCity_name() {
return city_name;
}
public void setCity_name(String city_name) {
this.city_name = city_name;
}
#XMLColumn(label = "state_id")
public String getState_id() {
return state_id;
}
public void setState_id(String state_id) {
this.state_id = state_id;
}
}
Here I Created Own Library For Converting Pojo classes to xml and xml to pojo classes.
Use Below Link(4Shared.com) at Comments to download Library to add for The Above Code.
String(XML in String) to List
1. FolderItem.java
<code>
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
#XmlAccessorType(XmlAccessType.FIELD)
public class FolderItem {
long itemId ;
String itemName;
String itemType;
String description;
String[] tags;
String path;
/* setters and getters
Annotations not required*/
}
</code>
2. FolderItems.java
<code>
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class FolderItems {
#XmlElement
private List<FolderItem> folderItem;
/* setter and getter */
}
</code>
3. Testing--main method
<code>
class Test{
public static void main(String[] args) throws Exception {
FolderItems f = (FolderItems)strToVo(content, FolderItems.class);
System.out.println(f);
}
static Object strToVo(String content, Class c) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = jc.createUnmarshaller();
return unmarshaller.unmarshal(new InputSource(new StringReader(content)));
}
}
</code>
4. XML in String
<code>
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
<FolderItems>
<folderItem>
<description>Lapse notice invoice for additional interests/additional insureds</description>
<itemId>480004439</itemId>
<itemName>Lapse_Invoice_AI</itemName>
<itemType>application/x-thunderhead-ddv</itemType>
<path>/Templates/Billing Center/Lapse_Invoice_AI</path>
<tags></tags>
</folderItem>
</FolderItems>
</code>
Related
It seems there is a bug in the MOXy. The piece of code below works perfectly when fields in class Request declared as metaInfo and then content, but test fails on unmarshalling with exception when fields declared in reverse order (content first and metaInfo second).
The exception thrown is:
Going with type: APPLICATION_XML
Original request = {content=Payload = {[one, two, three]}, metaInfo=requestMetaInfo = {confirmation=false}}
Marshaled as application/xml: <?xml version="1.0" encoding="UTF-8"?><request><collection><collection xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">one</collection><collection xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">two</collection><collection xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xsd:string">three</collection></collection><metaInfo><confirmation>false</confirmation></metaInfo></request>
Local Exception Stack:
Exception [EclipseLink-32] (Eclipse Persistence Services - 2.6.0.v20150309-bf26070): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: Trying to set value [[one, two, three]] for instance variable [collection] of type [java.util.Collection] in the object. The specified object is not an instance of the class or interface declaring the underlying field, or an unwrapping conversion has failed.
Internal Exception: java.lang.IllegalArgumentException: Can not set java.util.Collection field test2.TestCase2$Payload.collection to test2.TestCase2$RequestMetaInfo
Mapping: org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping[collection]
Descriptor: XMLDescriptor(test2.TestCase2$Payload --> [DatabaseTable(collection)])
at org.eclipse.persistence.exceptions.DescriptorException.illegalArgumentWhileSettingValueThruInstanceVariableAccessor(DescriptorException.java:703)
at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.setAttributeValueInObject(InstanceVariableAttributeAccessor.java:188)
at org.eclipse.persistence.mappings.DatabaseMapping.setAttributeValueInObject(DatabaseMapping.java:1652)
at org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping.setAttributeValueInObject(XMLCompositeCollectionMapping.java:741)
at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.setContainerInstance(XMLCompositeCollectionMappingNodeValue.java:265)
at org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endDocument(UnmarshalRecordImpl.java:628)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endDocument(AbstractSAXParser.java:745)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:515)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:648)
at org.eclipse.persistence.internal.oxm.record.XMLReader.parse(XMLReader.java:243)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:978)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:425)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:635)
at org.eclipse.persistence.internal.oxm.record.SAXUnmarshaller.unmarshal(SAXUnmarshaller.java:706)
at org.eclipse.persistence.internal.oxm.XMLUnmarshaller.unmarshal(XMLUnmarshaller.java:643)
at org.eclipse.persistence.jaxb.JAXBUnmarshaller.unmarshal(JAXBUnmarshaller.java:339)
at test2.TestCase2.main(TestCase2.java:67)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
Caused by: java.lang.IllegalArgumentException: Can not set java.util.Collection field test2.TestCase2$Payload.collection to test2.TestCase2$RequestMetaInfo
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:164)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:168)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:55)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:75)
at java.lang.reflect.Field.set(Field.java:741)
at org.eclipse.persistence.internal.descriptors.InstanceVariableAttributeAccessor.setAttributeValueInObject(InstanceVariableAttributeAccessor.java:141)
... 24 more
Here is a test to reproduce the problem.
package test2;
import org.eclipse.persistence.jaxb.JAXBContext;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
import org.eclipse.persistence.jaxb.MarshallerProperties;
import org.eclipse.persistence.jaxb.UnmarshallerProperties;
import org.eclipse.persistence.oxm.MediaType;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
/**
* Test that fails if Request.content field declared before than Request.metaInfo, but works well if
* Request.metaInfo goes first in declaration
*
* MOXy 2.6.0
*/
public class TestCase2 {
#XmlRootElement(name = "request")
#XmlAccessorType(XmlAccessType.FIELD)
public static class Request<T> {
#XmlAnyElement(lax = true)
private T content; // NB!: Causes test failure if declared before metaInfo, if declaration order is changed, things work
#XmlElement
private RequestMetaInfo metaInfo;
public Request() {
}
public Request(T content, RequestMetaInfo metaInfo) {
this.content = content;
this.metaInfo = metaInfo;
}
#Override
public String toString() {
return "request = {" + "content=" + content + ", metaInfo=" + metaInfo +'}';
}
}
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public static class RequestMetaInfo {
#XmlElement
private Boolean confirmation = false;
#Override
public String toString() {
return "requestMetaInfo = {" + "confirmation=" + confirmation +'}';
}
}
#XmlRootElement(name = "collection")
#XmlAccessorType(XmlAccessType.FIELD)
public static class Payload<T> {
#XmlElement
private Collection collection = new ArrayList();
public Payload(){}
public Payload(Collection<T> collection){
this.collection.addAll(collection);
}
public Collection<T> getCollection() {
return collection;
}
#Override
public String toString() {
return "Payload = {" + getCollection()+"}";
}
}
// Element name holding value of primitive types
public static final String VALUE_ELEMENT = "value";
// Attribute prefix in JSON
public static final String ATTRIBUTE_PREFIX = "#";
public static void main(String... args) {
try {
for (MediaType type : new MediaType[]{MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON}) {
System.out.println("Going with type: " + type);
JAXBContext context = (JAXBContext) JAXBContextFactory.createContext(
new Class[]{
Request.class,
RequestMetaInfo.class,
Payload.class
},
Collections.emptyMap());
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(MarshallerProperties.MEDIA_TYPE, type);
marshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
marshaller.setProperty(MarshallerProperties.JSON_ATTRIBUTE_PREFIX, ATTRIBUTE_PREFIX);
marshaller.setProperty(MarshallerProperties.JSON_VALUE_WRAPPER, VALUE_ELEMENT);
marshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
Request original = new Request(
new Payload(Arrays.asList("one","two","three")),
new RequestMetaInfo()
);
System.out.println("Original " + original.toString());
StreamResult result = new StreamResult(new StringWriter());
marshaller.marshal(original, result);
String generated = result.getWriter().toString();
System.out.println("Marshaled as " + type.getMediaType() + ": " + generated);
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, type);
unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
unmarshaller.setProperty(UnmarshallerProperties.JSON_ATTRIBUTE_PREFIX, ATTRIBUTE_PREFIX);
unmarshaller.setProperty(UnmarshallerProperties.JSON_VALUE_WRAPPER, VALUE_ELEMENT);
unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
Request unmarshalled = unmarshaller.unmarshal(new StreamSource(new StringReader(generated)), Request.class).getValue();
System.out.println("Unmarshaled " + unmarshalled.toString());
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Please any ideas what can be wrong?
After some debugging I found out, that bug could be probably in org.eclipse.persistence.internal.oxm.record.UnmarshalRecordImpl.endDocument().
The collection populatedContainerValues didn't get nulled after Payload.collection was unmarshalled. Then, when moxy unmarshalls metaInfo element it tries to process it as it were Payload.collection, assigning collection to Request.metaInfo, which causes exception.
I did ugly workaround (since I can't fix it) and just changed order of fields declaration in Request object, but I believe it will be fixed one day in MOXy.
UPDATE:
I filed a bug to MOXy bugzilla: https://bugs.eclipse.org/bugs/show_bug.cgi?id=468337
I had the same problem.
My solution:
#XmlMixed
#XmlAnyElement(lax = true)
private String content;
Enjoy ;)
I have spent some time to investigate what is the problem but I couldn't solve it. When I unmarshal below XML and marshal back I see different XML.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<one>test</one>
<three>\MySG\test.jsp</three>
<two>
<st>
<seeta>
<Source>
<problemtag xmlns="uuid:B89290D2-36FB-4EBC-A581-69B16D59EB92">
<p>deploy_test_page_renderingMetadata</p>
</problemtag>
</Source>
</seeta>
<Template id="tcm:1-63-32" title="Smart Compound Component Template"/>
<Publication id="tcm:0-1-1" title="Publication"/>
</st>
</two>
</root>
In the above xml only one tag (first one) expected remaining all (including namespace) are unexpected elements. Another application sends the above XML.
My Mapping are like this
package com.seeta.xml;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="root")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(name="one")
private String one;
public String getOne() {
return one;
}
public void setOne(String one) {
this.one = one;
}
#XmlElement(name="three")
private String three;
#XmlAnyElement
private List<Object> remaining = new ArrayList<Object>();
public String getThree() {
return three;
}
public void setThree(String three) {
this.three = three;
}
public List<Object> getRemaining() {
return remaining;
}
public void setRemaining(List<Object> remaining) {
this.remaining = remaining;
}
public String toString() {
return String.format("One [%s]-> Number of remaing elements [%d]-> three [%s]", one, remaining.size(), three);
}
}
Here is my simple code
package com.seeta.xml;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URL;
import java.net.URLDecoder;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class JaxbSample {
public Document getDOMDocument(InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
if (inputStream != null) {
return documentBuilder.parse(new InputSource(inputStream));
} else {
return documentBuilder.newDocument();
}
}
public Root unmarshall(Document document) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = (Root) unmarshaller.unmarshal(document);
return root;
}
public Document marshall(Root root) throws JAXBException, ParserConfigurationException, SAXException, IOException {
JAXBContext context = JAXBContext.newInstance(Root.class);
Marshaller marshaller = context.createMarshaller();
Document document = getDOMDocument(null);
marshaller.marshal(root, document);
return document;
}
private String transform(Document document) throws TransformerException {
StringWriter sw = new StringWriter();
TransformerFactory transformerFactory = TransformerFactory.newInstance();
Transformer transformer = transformerFactory.newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
transformer.transform(new DOMSource(document), new StreamResult(sw));
return sw.toString();
}
public void testUnmarshallMarshallUsingDocument() throws ParserConfigurationException, SAXException, IOException, JAXBException, TransformerException {
InputStream inputStream = this.getClass().getResourceAsStream("jaxb.xml");
Document document = getDOMDocument(inputStream);
Root root = unmarshall(document);
Document documentAfterMarshal = marshall(root);
String output = transform(documentAfterMarshal);
System.out.println(output);
}
public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException, JAXBException, TransformerException {
JaxbSample jaxbTest = new JaxbSample();
jaxbTest.testUnmarshallMarshallUsingDocument();
}
}
output is
<root>
<one>test</one>
<three>\MySG\test.jsp</three>
<two>
<st>
<seeta>
<Source>
<problemtag:problemtag xmlns="uuid:B89290D2-36FB-4EBC-A581-69B16D59EB92" xmlns:problemtag="uuid:B89290D2-36FB-4EBC-A581-69B16D59EB92">
<p>deploy_test_page_renderingMetadata</p>
</problemtag:problemtag>
</Source>
</seeta>
<Template id="tcm:1-63-32" title="Smart Compound Component Template"/>
<Publication id="tcm:0-1-1" title="Publication"/>
</st>
</two>
</root>
And also I tried following
I tried with NamespacePrefixMapper. I can able to give different namespace but not empty(""). I don't want any namespace at all.
new NamespacePrefixMapper() {
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
return "";
}
};
We don't have any xsd ( at least I don't know) in our project for trying unqualified thing
I really didn't understand QName thing
If all you want is to preserve the unused elements and marshall them back, I think you ought to be able to do something like this:
#XmlRootElement(name="Root")
#XmlAccessorType(XmlAccessType.FIELD)
class Root {
#XmlElement(name="One")
private String one;
#XmlAnyElement
private List<Any> otherElements;
}
class AnyAdapter extends XmlAdapter<Element,Any> {
#Override
public Any unmarshal(Element element) throws Exception {
return new Any(element);
}
#Override
public Element marshal(Any any) throws Exception {
return any.element;
}
}
#XmlJavaTypeAdapter(AnyAdapter.class)
class Any {
Element element;
Any(Element element) {
this.element = element;
}
}
I don't want any namespace at all.
You won't be able to accomplish this with JAXB alone. The #XmlAnyElement tells the unmarshaller to dump the elements that it can't process into your list. Those elements have namespaces attached. When you then marshal those elements, they'll be written with their namespaces.
One option is for you to parse the incoming XML with a namespace-unaware DOM parser, then unmarshall it using the DOM tree. There's an example of this in the Unmarshaller JavaDoc (which uses a namespace-aware parser; it should be obvious what to change to make it namespace-unaware).
I really didn't understand QName thing
Do you mean that you don't understand why the output is a qualified name, or why it picked the particular prefix? Or what QNames mean?
It's a qualified name because that's the most unambiguous way to represent the element.
I can't tell you why it picked this particular prefix; the JAXP serializer picks short names like "ns1", "ns2", and so on.
I'm trying to deserialize Json result from a web service into POJO.
ClientResource clientResource = new ClientResource("http://itunes.apple.com/search?term=marc+jordan&media=music&entity=album");
AlbumInfoResource resource = clientResource.wrap(AlbumInfoResource.class);
AlbumInfo albumInfo = resource.retrieve();
The resulting albumInfo is null, no exception is thrown.
I'm new to Restlet, what I'm doing wrong?
Interface:
public interface AlbumInfoResource {
#Get
public AlbumInfo retrieve();
}
The Json result from the web service looks like this:
{
"resultCount": 49,
"results": [
{
"wrapperType": "collection",
"collectionType": "Album",
"artistId": 771969,
"collectionId": 205639995,
"amgArtistId": 4640,
"artistName": "Marc Jordan",
"collectionName": "This Is How Men Cry",
"collectionCensoredName": "This Is How Men Cry",
"artistViewUrl": "http://itunes.apple.com/us/artist/marc-jordan/id771969?uo=4",
"collectionViewUrl": "http://itunes.apple.com/us/album/this-is-how-men-cry/id205639995?uo=4",
"artworkUrl60": "http://a5.mzstatic.com/us/r30/Music/cd/3f/13/mzi.rxpvpvdd.60x60-50.jpg",
"artworkUrl100": "http://a1.mzstatic.com/us/r30/Music/cd/3f/13/mzi.rxpvpvdd.100x100-75.jpg",
"collectionPrice": 9.9,
"collectionExplicitness": "notExplicit",
"trackCount": 10,
"copyright": "1999 Cafe Productions Inc.",
"country": "USA",
"currency": "USD",
"releaseDate": "2006-11-07T08:00:00Z",
"primaryGenreName": "Jazz"
},
...
...
}
]
}
The AlbumInfo class:
public class AlbumInfo implements Serializable {
private static final long serialVersionUID = 1L;
private int _resultCount;
private ArrayList<Album> _albums;
public AlbumInfo() {
_albums = new ArrayList<Album>();
}
public AlbumInfo(int resultCount, ArrayList<Album> albums) {
_resultCount = resultCount;
_albums = albums;
}
public int getResultCount() {
return _resultCount;
}
public void setResultCount(int resultCount) {
_resultCount = resultCount;
}
public ArrayList<Album> getAlbums() {
return _albums;
}
public void setAlbums(ArrayList<Album> _albums) {
this._albums = _albums;
}
}
The Album class would be to big to post here, but I have mapped the elements as reasonable as I could.
If you haven't already, you need to add Restlet's JacksonConverter to the list of registered converters:
List<ConverterHelper> converters = Engine.getInstance().getRegisteredConverters();
converters.add(new JacksonConverter());
and, of course, add org.restlet.ext.jackson.jar to your build path.
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
The following is how it could be done with MOXy by leveraging JAXB annotations:
AlbumInfo
package forum9966753;
import java.io.Serializable;
import java.util.ArrayList;
import javax.xml.bind.annotation.*;
#XmlType(propOrder={"resultCount", "albums"})
public class AlbumInfo implements Serializable {
private static final long serialVersionUID = 1L;
private int _resultCount;
private ArrayList<Album> _albums;
public AlbumInfo() {
_albums = new ArrayList<Album>();
}
public AlbumInfo(int resultCount, ArrayList<Album> albums) {
_resultCount = resultCount;
_albums = albums;
}
public int getResultCount() {
return _resultCount;
}
public void setResultCount(int resultCount) {
_resultCount = resultCount;
}
#XmlElement(name="results")
public ArrayList<Album> getAlbums() {
return _albums;
}
public void setAlbums(ArrayList<Album> _albums) {
this._albums = _albums;
}
}
Album
Below is a scaled down version of your Album class:
package forum9966753;
public class Album {
private String wrapperType;
public String getWrapperType() {
return wrapperType;
}
public void setWrapperType(String wrapperType) {
this.wrapperType = wrapperType;
}
}
jaxb.properties
To specify MOxy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain classes with the following entry:
javax.xml.bind.context.factory = org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
package forum9966753;
import java.io.InputStream;
import java.net.*;
import java.util.List;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.example.Customer;
public class JavaSEClient {
private static final String MEDIA_TYPE = "application/json";
public static void main(String[] args) throws Exception {
String uri = "http://itunes.apple.com/search?term=marc+jordan&media=music&entity=album";
URL url = new URL(uri);
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", MEDIA_TYPE);
JAXBContext jc = JAXBContext.newInstance(AlbumInfo.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
unmarshaller.setProperty("eclipselink.media-type", MEDIA_TYPE);
unmarshaller.setProperty("eclipselink.json.include-root", false);
InputStream xml = connection.getInputStream();
AlbumInfo albumInfo = unmarshaller.unmarshal(new StreamSource(xml), AlbumInfo.class).getValue();
connection.disconnect();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty("eclipselink.media-type", MEDIA_TYPE);
marshaller.setProperty("eclipselink.json.include-root", false);
marshaller.marshal(albumInfo, System.out);
}
}
Output
Below is the output from running the demo code. As the sample domain model only contains a couple properties the output is much smaller than the output. The JAXB mappings can easily be applied to map the rest of the document.
{
"resultCount" : 49,
"results" : [ {
"wrapperType" : "collection"
} ]
}
For More Information
MOXy as Your JAX-RS JSON Provider - Client Side
Try using JAXB annotations or use Jersey for JSON mappings. This manual could be useful for you: link
Recently I had to develop an Android app with Restlet framework and I spent a lot of time to understand how to deserialize a JSONObject.
Here I'm going t explain my method.
I also published a complete Android App on GitHub here:
https://github.com/alchimya/android-restlet
Restlet 2.3.2 includes Gson lib.
With Gson is very simple to map and deserialize a resource.
1) Map your entity base with a class as following:
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
public class Album implements Serializable {
#SerializedName("wrapperType")
private String wrapperType;
#SerializedName("collectionType")
private String collectionType;
#SerializedName("artistId")
private String artistId;
public String getWrapperType() {
return wrapperType;
}
public void setWrapperType(String wrapperType) {
this.wrapperType = wrapperType;
}
public String getCollectionType() {
return collectionType;
}
public void setCollectionType(String collectionType) {
this.collectionType = collectionType;
}
public String getArtistId() {
return artistId;
}
public void setArtistId(String artistId) {
this.artistId = artistId;
}
......
......
......
}
Note: in the previous class each property has an annotation (#SerializedName) to map the corresponding JSON field. For further informations see this tutorial:
http://www.javacodegeeks.com/2011/01/android-json-parsing-gson-tutorial.html
2) Create a class with a List attribute:
public class Albums {
public List<Album> results;
}
3) Consume your resource with Restlet
String uri="http://itunes.apple.com/search?term=marc+jordan&media=music&entity=album";
ClientResource resource = new ClientResource(url);
Representation rep = resource.get();
JsonRepresentation represent = new JsonRepresentation(rep);
JSONObject jsonobject = represent.getJsonObject();
String jsonText = jsonobject.toString();
Gson gson = new Gson();
Albums response = gson.fromJson(jsonText, Albums.class);
Into response.results there will be all deserialized items.
I have following XML on input:
<root>
<response1></response1>
</root>
or
<root>
<response2></response2>
</root>
And there is possibly a lot of response tags each of which I need to map to a single Response class because they have almost the same structure.
Is it easy to do in JAXB?
Thanks.
This could be done with the #XmlElements annotation:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElements({
#XmlElement(name="response1", type=Response.class),
#XmlElement(name="response2", type=Response.class),
#XmlElement(name="response3", type=Response.class)
})
private Response response;
}
http://blog.bdoughan.com/2010/10/jaxb-and-xsd-choice-xmlelements.html
http://blog.bdoughan.com/2011/04/xml-schema-to-java-xsd-choice.html
Well, sure. In XSD file, define a type first:
<xs:complexType name="response">
<!-- define type here -->
</xs:complexType>
Now define your elements using it:
<xs:element name="response1" type="response"/>
<xs:element name="response2" type="response"/>
<!-- and so on and so forth -->
I got it to work this way. It uses an XMLStreamReader as the source, and a StreamReaderDelegate to intercept and rewrite the element names before they reach jaxb.
The main test class:
package grimbo.test.jaxb;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.util.StreamReaderDelegate;
public class JaxbTest {
public static <T> T unmarshal(Class<T> clazz, InputStream inputStream) throws JAXBException, XMLStreamException,
FactoryConfigurationError {
XMLStreamReader r = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
MyXMLStreamReader my = new MyXMLStreamReader(r);
String packageName = clazz.getPackage().getName();
JAXBContext jc = JAXBContext.newInstance(packageName);
Unmarshaller u = jc.createUnmarshaller();
return (T) u.unmarshal(my);
}
public static void main(String[] args) throws Exception {
String xml1 = "<root>" + "<response1>test1</response1>" + "</root>";
String xml2 = "<root>" + "<response2>test2</response2>" + "</root>";
Object ob = unmarshal(Response.class, new ByteArrayInputStream(xml1.getBytes()));
System.out.println(ob);
ob = unmarshal(Response.class, new ByteArrayInputStream(xml2.getBytes()));
System.out.println(ob);
}
static class MyXMLStreamReader extends StreamReaderDelegate {
public MyXMLStreamReader(XMLStreamReader reader) {
super(reader);
}
public QName getName() {
QName qname = super.getName();
return qname;
}
public String getLocalName() {
String localName = super.getLocalName();
if (localName.matches("response\\d+")) {
return "response";
}
return localName;
}
}
}
The Response class is:
package grimbo.test.jaxb;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "root", namespace = "")
public class Response {
String response;
public String getResponse() {
return response;
}
public void setResponse(String response) {
this.response = response;
}
#Override
public String toString() {
return "Response [response=" + response + "]";
}
}
And there's a jaxb.index file in this package too, that declares the Response class:
Response
The output of the test is:
Response [response=test1]
Response [response=test2]
Is this any help?
The easiest thing to do imo would be to make the response element an unbounded list in your schema then once you have created your bindings you can iterate throught the list of response nodes.
I tried to map multiple tag to single class using JAXB with same format mention above.
Now define your elements using it:
<xs:element name="response1" type="response"/>
<xs:element name="response2" type="response"/>
<!-- and so on and so forth -->
While unmarshalling JAXB validates the XML(format) with response class format mentioned in XSD file ,but its is giving me JAXB.element class object instead of response object.
Please suugest with answer..
This question already has an answer here:
Closed 12 years ago.
Possible Duplicate:
how to write test case in java
hi
I created one class in which I have one constructor as follows:
public class ABC {
private static String host;
private static String port;
private static String browser;
private static String url;
private static String fullurl;
public ABC(){
try {
File file = new File("Element.xml");
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(file);
doc.getDocumentElement().normalize();
please tell me test case for constructor:
First of all, doc is not the output. It is a local variable inside the constructor and can't be tested/validated in a unit test. But on the other hand, you can rely on the (tested) Parser. It will produce the correct DOM for the given input file.
You may want to test, if the values from the input file are stored to the fields as specified.
So create an input file with legal values, create an instance and assert if the fields contain the correct values:
#Test
public void testABCWithLegalValues() {
ABC abc = new ABC("correct.xml"); // NOTE! I invented a new constructor
// to allow passing test config files!!
assertEquals("www.google.com", abc.getHost());
assertEquals(80, abc.getPort());
// ...
}
This is an example test method based on jUnit 4.
Other tests would feed the constructor with malformed xml files or files with illegal data (like a port Address > 65535) and verify that the class reacts as specified.
I have no idea what kinds of test case you need.
However, your can verify the final result in this way: feeding the xml and asserting the values about host, port, browser, url, fullurl.
Maybe you need refactor it to make xml text or file set by test-case.
Your class is performing two distinct tasks:
Reading a file and parsing it as a Document
Processing the Document to determine host, port, browser, url and fullurl
Since this currently all occurs within the constructor and the file name is hardcoded, this class is pretty hard to unit test.
If you can modify the class, then here are my suggestions to make this class testable:
Don't hardcode the name of the file to be parsed. I would pass it as a constructor argument here because you don't need the fileName later on so no need to keep it as a private field.
Separate the tasks, let the constructor read the file and create a separate method to process the document.
Since you wanted the codez, here is the modified class:
import java.io.File;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.apache.log4j.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class ABC {
private static final Logger LOG = Logger.getLogger(ABC.class);
private static final String DEFAULT_FILENAME = "Element.xml";
private String host;
private String port;
private String browser;
private String url;
private String fullurl;
public class AbcFileAccessException extends Exception {
private static final long serialVersionUID = 1L;
public AbcFileAccessException(Exception e) {
super(e);
}
}
public ABC() throws AbcFileAccessException {
this(DEFAULT_FILENAME);
}
public ABC(String fileName) throws AbcFileAccessException {
File file = new File(fileName);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
DocumentBuilder db = dbf.newDocumentBuilder();
process(db.parse(file));
} catch (ParserConfigurationException e) {
throw new AbcFileAccessException(e);
} catch (SAXException e) {
throw new AbcFileAccessException(e);
} catch (IOException e) {
throw new AbcFileAccessException(e);
}
}
public ABC(Document document) {
process(document);
}
public void process(Document document) {
if (document == null) {
throw new IllegalArgumentException("Document may not be null");
}
document.getDocumentElement().normalize();
LOG.info("Root element " + document.getDocumentElement().getNodeName());
NodeList nodeLst = document.getElementsByTagName("selenium");
for (int s = 0; s < nodeLst.getLength(); s++) {
Node fstNode = nodeLst.item(s);
if (fstNode.getNodeType() == Node.ELEMENT_NODE) {
Element fstElmnt = (Element) fstNode;
NodeList fstNmElmntLst = fstElmnt.getElementsByTagName("name");
Element fstNmElmnt = (Element) fstNmElmntLst.item(0);
NodeList fstNm = fstNmElmnt.getChildNodes();
String name = ((Node) fstNm.item(0)).getNodeValue();
NodeList lstNmElmntLst = fstElmnt.getElementsByTagName("value");
Element lstNmElmnt = (Element) lstNmElmntLst.item(0);
NodeList lstNm = lstNmElmnt.getChildNodes();
String value = ((Node) lstNm.item(0)).getNodeValue();
if (name.equals("host")) {
host = value;
}
if (name.equals("port")) {
port = value;
}
if (name.equals("browser")) {
browser = value;
}
if (name.equals("url")) {
url = value;
}
if (name.equals("fullurl")) {
fullurl = value;
}
}
}
}
public String getHost() {
return host;
}
public String getPort() {
return port;
}
public String getBrowser() {
return browser;
}
public String getUrl() {
return url;
}
public String getFullurl() {
return fullurl;
}
}
Other improvements I made :
Avoid static fields for runtime data like this. If they are private (as in your example) then they can just be instance field, seeing you are already creating a (non-singleton) instance of the class. If you intended them to be accessed by other classes it is even worse, because those other classes could access the fields like ABC.host which makes them hard to test and locked in to you implementation class. Let's not go into that now (-:
NEVER call setters from a contructor (see http://www.javapractices.com/topic/TopicAction.do?Id=215 for an explanation).
Scope try-catch blocks as narrowly as possible (or practical). This makes your code more readable because it is clear where the exceptions are being thrown.
Catch each exception type separately. Bundeling them together makes the code less readable. I agree this is a pain for some parts of the API (try using reflection), but it is good practice. Assume a developer should be able to read and understand your code from a printout (so without hovering and code navigation features of your IDE).
Don't handle exceptions by calling printStacktrace, logging an error or throwing a RuntimeException if you can avoid it. If you do, at least document these error conditions thoroughly. It is ok to create your own exception types for error conditions, this makes for a very understandable API (so other developers don't have to delve into your code, but can use the class after reading the JavaDoc).
Don't use System.out.println for logging, use a logging framework like Log4j.
This class can now be tested as follows:
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import xcon.pilot.ABC.AbcFileAccessException;
public class ABCTest {
private Document document;
#Before
public void setUp() throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
document = builder.newDocument();
}
#Test
public void testProcess() throws ParserConfigurationException,
AbcFileAccessException, TransformerFactoryConfigurationError,
TransformerException {
Element root = (Element) document.createElement("root");
document.appendChild(root);
String host = "myhost";
String port = "myport";
String browser = "mybrowser";
String url = "myurl";
String fullurl = "myfullurl";
root.appendChild(createElement("host", host));
root.appendChild(createElement("port", port));
root.appendChild(createElement("browser", browser));
root.appendChild(createElement("url", url));
root.appendChild(createElement("fullurl", fullurl));
// for your convenience
printXml();
ABC instance = new ABC(document);
Assert.assertEquals(host, instance.getHost());
Assert.assertEquals(port, instance.getPort());
Assert.assertEquals(browser, instance.getBrowser());
Assert.assertEquals(url, instance.getUrl());
Assert.assertEquals(fullurl, instance.getFullurl());
}
private Element createElement(String name, String value) {
Element result = (Element) document.createElement("selenium");
Element nameElement = document.createElement("name");
nameElement.setTextContent(name);
result.appendChild(nameElement);
Element valueElement = document.createElement("value");
valueElement.setTextContent(value);
result.appendChild(valueElement);
return result;
}
private void printXml() throws TransformerConfigurationException,
TransformerFactoryConfigurationError, TransformerException {
Transformer transformer = TransformerFactory.newInstance()
.newTransformer();
Source source = new DOMSource(document);
Result output = new StreamResult(System.out);
transformer.transform(source, output);
}
}
This tests your Document processing logic. Testing the reading and parsing of files is notably tricky and can't really be seen as unit testing because you are always dependent on the operating system and its filesystem. I usually leave that as part of integration testing and build/deployment support. It helps to build good sanity checks and error handling in your code so missing/incorrect files are reported clearly and early.
Hope this helped you.