JAXB Error: unexpected element when unmarshalling - java

Could someone help me understand why I'm getting this error:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"items"). Expected elements are <{}item>
I've new to JAX-B but been stuck on this all day, I really don't understand whats happening and any help is really appreciated, thanks a lot.
Item Class:
#XmlRootElement
public class Item {
private String itemID;
private String itemDescription;
//need to have a constructor with no params
public Item(){
}
//Constructor: sets object vars
public Item(String itemID, String itemDescription) {
this.itemID = itemID;
this.itemDescription = itemDescription;
}
#XmlAttribute
//getters and setters
public String getID() {
return itemID;
}
public void setId(String id) {
itemID= id;
}
#XmlElement
public String getDescription() {
return itemDescription;
}
public void setDescription(String description) {
itemDescription = description;
}
Unmarshalling code:
resource = client.resource("http://localhost:8080/testProject/rest/items");
ClientResponse response= resource.get(ClientResponse.class);
String entity = response.getEntity(String.class);
System.out.println(entity);
JAXBContext context = JAXBContext.newInstance(Item.class);
Unmarshaller um = context.createUnmarshaller();
Item item = (Item) um.unmarshal(new StringReader(entity));
And this is the XML i'm trying to parse:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<items>
<item id="1">
<description>Chinos</description>
</item>
<item id="2">
<description>Trousers</description>
</item>
</items>
Here is the Web Service that is creating the XML:
#GET
#Produces(MediaType.TEXT_XML)
public List<Item> getItemsBrowser(){
java.sql.Connection connection;
java.sql.Statement statement;
List<Item> items = new ArrayList<Item>();
ResultSet resultSet = null;
try {
connection = dataSource.getConnection();
statement = connection.createStatement();
String query = "SELECT * FROM ITEMS";
resultSet = statement.executeQuery(query);
// Fetch each row from the result set
while (resultSet.next()) {
String a = resultSet.getString("itemID");
String b = resultSet.getString("itemDescription");
//Assuming you have a user object
Item item = new Item(a, b);
items.add(item);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return items;
}

The class you're creating the JAXBContext from is Item.class, but the XML contains a list called items which in turn contains distinct item entries. You would need another class that wraps a
List<Item>
for this to work.
Here's a full working example:
The Items class:
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Items {
private List<Item> items;
#XmlElement(name="item")
public List<Item> getItems() {
return items;
}
public void setItems(List<Item> items) {
this.items = items;
}
}
Note that there is an #XmlElement annotation on the items property, because the actual elements are called "item" in the XML.
The Item class:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Item {
private String itemID;
private String itemDescription;
// need to have a constructor with no params
public Item() {}
public Item(String itemID, String itemDescription) {
this.itemID = itemID;
this.itemDescription = itemDescription;
}
#XmlAttribute
public String getId() {
return itemID;
}
public void setId(String id) {
itemID = id;
}
#XmlElement
public String getDescription() {
return itemDescription;
}
public void setDescription(String description) {
itemDescription = description;
}
}
And a unit test:
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.junit.Test;
public class JAXBTest {
#Test
public void xmlIsUnmarshalled() throws JAXBException {
JAXBContext context = JAXBContext.newInstance(Items.class);
Unmarshaller um = context.createUnmarshaller();
Items items = (Items) um.unmarshal(new File("items.xml"));
assertNotNull(items);
assertNotNull(items.getItems());
assertEquals(2, items.getItems().size());
assertEquals("Chinos", items.getItems().get(0).getDescription());
assertEquals("Trousers", items.getItems().get(1).getDescription());
assertEquals("1", items.getItems().get(0).getId());
assertEquals("2", items.getItems().get(1).getId());
}
}

Since youa are using the Jersey cleint APIs you could do the following and avoid creating the Items class:
import java.util.List;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.GenericType;
import com.sun.jersey.api.client.WebResource;
public class JerseyClient {
public static void main(String[] args) {
Client client = Client.create();
WebResource resource = client.resource(""http://localhost:8080/testProject/rest/items"");
List<Item> items = resource.accept("application/xml").get(new GenericType<List<Item>>(){});
System.out.println(items.size());
}
}
For More Information
http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-55.html

Related

How to get a value between tags with XML format using jaxb

I have a xml format like below:
<list>12
<item name="a">
<child parent="b" age="1">David Beckham</child>
</item>
</list>
The question is how could i extract 12 using JAXB? Which annotation supports it? Thank a lot.
Following is the working example.
import java.io.StringReader;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlElementRefs;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.transform.stream.StreamSource;
public class TestJAXBMixed {
public static void main(String[] args) throws Exception {
final String str =
"<list>12<item name=\"a\"><child parent=\"b\" age=\"1\">David Beckham</child></item></list>";
final JAXBContext jaxbContext = JAXBContext.newInstance(Child.class, Item.class, ListElement.class);
final JAXBElement<ListElement> obj = jaxbContext.createUnmarshaller().unmarshal(new StreamSource(new StringReader(str)), ListElement.class);
// The following is an array of objects representing the <list> content in order,
// i.e. it is a sequence of a String (12) and an Object (Item)
final List<Object> content = obj.getValue().getContent();
System.out.println(content);
}
}
#XmlRootElement(name="child")
class Child {
private String parent;
private String age;
private String text;
public String getParent() {
return parent;
}
#XmlAttribute(name="parent")
public void setParent(String parent) {
this.parent = parent;
}
public String getAge() {
return age;
}
#XmlAttribute(name="age")
public void setAge(String age) {
this.age = age;
}
public String getText() {
return text;
}
#XmlValue
public void setText(String text) {
this.text = text;
}
}
#XmlRootElement(name="item")
class Item {
private String name;
private Child child;
public String getName() {
return name;
}
#XmlAttribute(name="name")
public void setName(String name) {
this.name = name;
}
public Child getChild() {
return child;
}
public void setChild(Child child) {
this.child = child;
}
}
#XmlRootElement(name="list")
class ListElement {
private List<Object> content;
public List<Object> getContent() {
return content;
}
#XmlMixed
#XmlElementRefs({
#XmlElementRef(name="item", type=Item.class)
})
public void setContent(List<Object> content) {
this.content = content;
}
}
SimpleXml can do it:
final String data = ...
final SimpleXml simple = new SimpleXml();
final Element element = simple.fromXml(data);
System.out.println(element.text);
Will output:
12
From maven central:
<dependency>
<groupId>com.github.codemonstur</groupId>
<artifactId>simplexml</artifactId>
<version>1.4.0</version>
</dependency>

Creating multiple XML files from a hashmap in Java

I'm trying to create a XML file from a HashMap. For each key of the hash i want an XML file. The value of the key is an ArrayList of Objects. I am using JAXB but the XML files are not created, as the output is not XML valid.
The object class:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Product")
public class Product implements Comparable<Product>{
String ID,description, gtin;
double price;
String date;
Product()
{
}
public String toString()
{
return ID+" "+description+" "+gtin+" "+price+" "+date;
}
public String getID() {
return ID;
}
#XmlElement
public void setID(String ID) {
this.ID = ID;
}
public String getDescription() {
return description;
}
#XmlElement
public void setDescription(String description) {
this.description = description;
}
public String getGtin() {
return gtin;
}
#XmlElement
public void setGtin(String gtin) {
this.gtin = gtin;
}
public double getPrice() {
return price;
}
#XmlElement
public void setPrice(Double price) {
this.price = price;
}
}
The class where i try to create the XMLs:
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class CreateXML {
static void create(HashMap<String, ArrayList<Product> > map) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(ProdsList.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Set setOfKeys = map.keySet();
Iterator iterator = setOfKeys.iterator();
while (iterator.hasNext()) {
String keys = (String) iterator.next();
String filename= "C:\\Users\\As\\Desktop\\Sups\\"+keys+22+".xml";
File file = new File(filename);
ArrayList<Product> value = map.get(keys);
jaxbMarshaller.marshal(value, file);
jaxbMarshaller.marshal(value, System.out);
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
The class for the root of the xml:
import java.util.*;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
//#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="Products")
//#XmlSeeAlso({ArrayList.class})
class ProdsList {
#XmlElement(name="Product")
ArrayList<Product> prods;
public ProdsList(){
prods=new ArrayList<Product>();
}
public ArrayList<Product> getProducts() {
return prods;
}
public void setProducts(ArrayList<Product> prods) {
this.prods = prods;
}
}
How can i fix this. Thanks in advance.
You need to marshal an instance of ProdsList. Instead you are trying to marshall
an ArrayList of Products.
Change
jaxbMarshaller.marshal(value, file);
jaxbMarshaller.marshal(value, System.out);
To
jaxbMarshaller.marshal(new ProdsList(value), file);
jaxbMarshaller.marshal(new ProdsList(value), System.out);

jaxb unMarshaller failure ClassCastException because two xml elements are the same name. Why?

I am having an issue with my unmarshaller. I have a file that looks like the following:
<Employee xmlns="namespace here">
<Employee>
<Id>2</Id>
<Name>idk</Name>
</Employee>
</Employee>
The problem is the root element and the list of elements are the same name "Employee". When I go to unmarshal I get a classcastexception.
#XmlRootElement(name="Employee")
public class EmployeeInformation {
List<EmployeeInformationElement> elements;
private String errorCode;
private String errorMessage;
public List<EmployeeInformationElement> getElements() {
return elements;
}
#XmlElement(name="Employee")
public void setElements(List<EmployeeInformationElement> elements) {
this.elements = elements;
}
public String getErrorCode() {
return errorCode;
}
#XmlElement(name="ErrorCode")
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
#XmlElement(name="ErrorMessage")
public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}
I am able to use this code to marshal a file that looks exactly like the file I need to unmarshal. So I am confused. What is missing so when I unmarshal, the unmarshaller does not give me the following exception:
java.lang.ClassCastException: XXXX.EmployeeInformationElement cannot be cast to XXXX.EmployeeInformation
Unable to reproduce (tested on Java 1.8.0_65).
Since you didn't provide an MCVE (Minimal, Complete, and Verifiable example), here is one that works.
Only known difference is that namespace was removed for simple testing.
import java.io.StringReader;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
public class Test {
public static void main(String[] args) throws Exception {
String xml = "<Employee>\r\n" +
"<Employee>\r\n" +
" <Id>2</Id>\r\n" +
" <Name>idk</Name>\r\n" +
"</Employee>\r\n" +
"</Employee>\r\n";
JAXBContext jaxbContext = JAXBContext.newInstance(EmployeeInformation.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
EmployeeInformation empInfo = (EmployeeInformation)unmarshaller.unmarshal(new StringReader(xml));
System.out.println(empInfo);
}
}
#XmlRootElement(name="Employee")
class EmployeeInformation {
private List<EmployeeInformationElement> elements;
#XmlElement(name="Employee")
public List<EmployeeInformationElement> getElements() {
return elements;
}
public void setElements(List<EmployeeInformationElement> elements) {
this.elements = elements;
}
}
class EmployeeInformationElement {
private int id;
private String name;
#XmlElement(name="Id")
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
#XmlElement(name="Name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}

JAXB unmarshalling elements with same name

this is my xml structure
<catalog>
<course>
<course_id></course_id>
<subjects>
<subject>
<subject_id></subject_id>
</subject>
<subject>
<subject_id></subject_id>
</subject>
</subjects>
</course>
</catalog>
So, i'v tried to bind this xml to a class using JAXB Unmarshalling, but the result was nothing.
I was thinking, i have 2 base elements, course and subject, so i built 2 classes based on these elements.
This to control the course tag
#XmlRootElement(name="catalog")
#XmlAccessorType(XmlAccessType.FIELD)
public class curso {
#XmlElement(name="course_id")
int course_id;
#XmlElementWrapper(name="subjects")
#XmlElement(name="subject")
List <subject> subjects = new ArrayList<>();
public void setCourse_id(int curso_id) {
this.curso_id = curso_id;
}
public void setSubjects(List<subject> subjects) {
this.subjects = subjects;
}
}
And This to control the subject tag.
public class subject {
String subject_id;
#XmlElement(name="subject_id")
public void setSubjectId(String id) {
this.subject_id = id;
}
}
I made some to string functions, and my output was nothing.
What is the problem?
The course element also have a wrapper tag <course> So either you need to change you xml to remove <catalog> tag and make <course> as the root. Or you should create a new class catalog and make course as a field. Like
#XmlRootElement(name="catalog")
#XmlAccessorType(XmlAccessType.FIELD)
class catalog {
#XmlElement(name="course")
curso course;
public curso getCourse() {
return course;
}
public void setCourse(curso course) {
this.course = course;
}
#Override
public String toString() {
return "catalog [course=" + course + "]";
}
}
A complete example
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="catalog")
#XmlAccessorType(XmlAccessType.FIELD)
class catalog {
#XmlElement(name="course")
curso course;
public curso getCourse() {
return course;
}
public void setCourse(curso course) {
this.course = course;
}
#Override
public String toString() {
return "catalog [course=" + course + "]";
}
}
class curso {
#XmlElement(name = "course_id")
int course_id;
#XmlElementWrapper(name = "subjects")
#XmlElement(name = "subject")
List<subject> subjects = new ArrayList<>();
public void setCourse_id(int curso_id) {
this.course_id = curso_id;
}
public void setSubjects(List<subject> subjects) {
this.subjects = subjects;
}
#Override
public String toString() {
return "curso [course_id=" + course_id + ", subjects=" + subjects + "]";
}
}
class subject {
String subject_id;
#XmlElement(name = "subject_id")
public void setSubjectId(String id) {
this.subject_id = id;
}
#Override
public String toString() {
return "subject [subject_id=" + subject_id + "]";
}
}
public class JaxbExample2 {
public static void main(String[] args) {
try {
File file = new File("file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(catalog.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
catalog customer = (catalog) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}

Converting JSON object to string in JAXB

Am writing an Webservice endpoint which will produce JSON and XML response. Here i would like to convert an object to JSON and setting it to string. When i try to do with the below code
Webservice Endpoint
package com.test1;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;`
#Path("v1")
public class Impl1 {
#POST
#Path("method")
#Produces({"text/xml","application/json"})
public XML method() throws JSONException
{
//JSONObject obj = new JSONObject();
JSONArray ary = new JSONArray();
Main main = new Main();`
List<Student> details = new ArrayList<Student>() ;
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
s1.setId("ID1");
s1.setValue("1");
s2.setId("ID2");
s2.setValue("2");
s3.setId("ID3");
s3.setValue("3");
details.add(s1);
details.add(s2);
details.add(s3);
main.setDetails(details);
ary.put(details);
Employee emp = new Employee();
emp.setName("Mike");
emp.setSalary(1000);
XML xml = new XML();
xml.setDetails(ary.toString());
xml.setEmp(emp);
xml.setId("1");
return xml;
}
}
XML class (JAXB)
package com.test1;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class XML {
String id;
Employee emp;
String details;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Employee getEmp() {
return emp;
}
public void setEmp(Employee emp) {
this.emp = emp;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
}
Student Class
package com.test1;
public class Student {
String id;
String Value;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getValue() {
return Value;
}
public void setValue(String value) {
Value = value;
Main Class
package com.test1;
import java.util.List;
public class Main {
List<Student> details;
public List<Student> getDetails() {
return details;
}
public void setDetails(List<Student> details) {
this.details = details;
}
}
So when i hit my service am getting response as
{
"details" : "[[{\"id\":\"ID1\",\"value\":\"1\"},{\"id\":\"ID2\",\"value\":\"2\"},{\"id\":\"ID3\",\"value\":\"3\"}]]",
"emp" : {
"name" : "Arun",
"salary" : "1000.0"
},
"id" : "1"
}
Expected String valuse as
[{"id":"ID1","value":"1"},{"id":"ID2","value":"2"},{"id":"ID3","value":"3"}]
My Question is Why JSONArray which was converted as String contains "\" on every key value pair. is there any way to overcome this?
Use Jackson or google-gson or any other library.
For example
http://howtodoinjava.com/2014/06/16/jackson-examples-convert-java-object-to-from-json/

Categories

Resources