XML to Java object deserialization using Jackson - java

I have a XML file which i want to deserialize using Jackson.But i am getting the above Exception.
<students>
<student>
<Name>Tapishnu2</Name>
<Age>25</Age>
<Department>Computer</Department>
</student>
<student>
<Name>Tapishnu1</Name>
<Age>25</Age>
<Department>Computer</Department>
</student>
<student>
<Name>Tapishnu2</Name>
<Age>25</Age>
<Department>Computer</Department>
</student>
<student>
<Name>Tapishnu3</Name>
<Age>25</Age>
<Department>Computer</Department>
</student>
</students>
I have a POJO class like this
#JacksonXmlRootElement(localName = "students")
public class Students {
#JacksonXmlProperty(localName = "student")
private Student[] student;
/*public Students(){
}*/
public Students( Student[] student) {
super();
this.student = student;
}
public Student[] getStudent() {
return student;
}
public void setStudent(Student[] student) {
this.student = student;
}
#Override
public String toString() {
return "students [student=" + Arrays.toString(student) + "]";
}
}
public class Student {
#JacksonXmlProperty(localName = "Name")
String Name;
#JacksonXmlProperty(localName = "Age")
String Age;
#JacksonXmlProperty(localName = "Department")
String Department;
public String getName() {
return Name;
}
public void setName(String Name) {
this.Name = Name;
}
public String getAge() {
return Age;
}
public void setAge(String Age) {
this.Age = Age;
}
public String getDepartment() {
return Department;
}
public void setDepartment(String department) {
Department = department;
}
#Override
public String toString() {
return "Student [Name=" + Name + ", Age=" + Age + ", Department="
+ Department + "]";
}
}
Main class
file = new File("C://Avatar//Students.xml");
System.out.println(file.canRead());
XmlMapper mapper = new XmlMapper();
Students openCredentials = mapper.readValue(file, Students.class);
I am getting the following Error
com.fasterxml.jackson.databind.JsonMappingException: No suitable constructor found for type [simple type, class com.Team.Students]: can not instantiate from JSON object (missing default constructor or creator, or perhaps need to add/enable type information?)
at [Source: C:\Avatar\Students.xml; line: 2, column: 3]
I guess there is a problem with the annotations.I am a newbie to Jackson.So a help will be appreciated.

You need a no-arg constructor for Jackson to deserialize JSON to Java objects. In the deserialization process Jackson uses the attributes/methods either directly rather than constructors.
Try adding
public Students() {
super();
this.student = new Student[]{};
}
or maybe
public Students() {
this(new Student[]{});
}

Related

I want to 'pase xml and serve objects in rest api

` This is my xml code.Iam very new to restservice.
<?xml version="1.0" encoding="UTF-8"?>
<departments>
<deptname name="Research">
<employee>
<eid>r-001</eid>
<ename>Dinesh R</ename>
<age>35</age>
<deptcode>d1</deptcode>
<deptname>Research</deptname>
<salary>20000</salary>
</employee>
</deptname>
<deptname name="Sales">
<employee>
<eid>s-001</eid>
<ename>Kanmani S</ename>
<age>35</age>
<deptcode>d2</deptcode>
<deptname>Sales</deptname>
<salary>30000</salary>
</employee>
</deptname>
</departments>
By using this xml i want to create Restservice.I have tried , i created java classes for that(i don't know that correct or not ).but i am stuck in controller in that area how i will mapping.
Here is a simplest way, in my opinion
1) create a Departments pojo
2) create Department pojo which will be composed (composition) into departments
3) create a regular springboot controller, ensure the controller method produces and consumes application/xml
4) include below dependency in your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
here is my example,
Departments.java
import org.springframework.stereotype.Component;
#Component
public class Departments {
private List<Department> department;
public List<Department> getDepartment() {
return department;
}
public void setDepartment(List<Department> department) {
this.department = department;
}
}
Department.java
import org.springframework.stereotype.Component;
#Component
public class Department {
private String name;
private String id;
private int employeeCount;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getEmployeeCount() {
return employeeCount;
}
public void setEmployeeCount(int employeeCount) {
this.employeeCount = employeeCount;
}
#Override
public String toString() {
return "Department [name=" + name + ", id=" + id + ", employeeCount=" +
employeeCount + "]";
}
public Department() { }
public Department(String name) {
this.name = name;
}
public Department(String name, String id) {
this.name=name;
this.id=id;
}
public Department(String name, String id, int employeeCount) {
this.name=name;
this.id=id;
this.employeeCount = employeeCount;
}
}
SpringBootApplication.java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication(scanBasePackages = {"test.controllers","test.main", "test.model"})
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
}
SpringController
#RestController
public class GreetingController {
#RequestMapping("/hello/{name}")
String hello(#PathVariable String name) {
return "Hello, " + name + "!";
}
#PostMapping(path = "/departments", produces = MediaType.APPLICATION_XML_VALUE, consumes = MediaType.APPLICATION_XML_VALUE)
#ResponseBody
Departments newEmployee(#RequestBody List<Department> departments) {
Departments departmentsObj = new Departments();
for(Department department : departments) {
System.out.println(department);
}
departmentsObj.setDepartment(departments);
return departmentsObj;
}
}

Selective marshalling object

I need to execute a selective marshalling object. For example:
There is a class Contact:
#XmlRootElement(name = "contact")
public class Contact {
private String name;
private String number;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Marshalling the object:
public static void main(String[] args) throws JAXBException {
Contact contact = new Contact();
contact.setAddress("5 Av.");
contact.setName("John");
contact.setNumber("5555555");
JAXBContext context = JAXBContext.newInstance(Contact.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(contact, System.out);
}
As a result we have:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact>
<address>5 street</address>
<name>John</name>
<number>5555555</number>
</contact>
Is there any simple way to perform a selective marshalling? For example, only the address to get at the output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact>
<address>5 street</address>
</contact>
Thanks!
When unspecified, the default is as-if the following annotation is on the class:
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
That means that all public member will be used by JAXB, i.e. all your getter methods.
You can either keep that default and suppress the getter methods you don't want, or you can change the default and explicitly mark the getter methods you do want processed.
To suppress a getter method, annotate with #XmlTransient:
Prevents the mapping of a JavaBean property/type to XML representation.
To change default, annotate with #XmlAccessorType(XmlAccessType.NONE):
None of the fields or properties is bound to XML unless they are specifically annotated with some of the JAXB annotations.
Then explicitly annotate desired getter methods with #XmlElement:
Maps a JavaBean property to a XML element derived from property name.
Using #XmlTransient
#XmlRootElement(name = "contact")
class Contact {
private String name;
private String number;
private String address;
#XmlTransient
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlTransient
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Using #XmlAccessorType(XmlAccessType.NONE)
#XmlRootElement(name = "contact")
#XmlAccessorType(XmlAccessType.NONE)
class Contact {
private String name;
private String number;
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
#XmlElement
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
Output (from both)
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contact>
<address>5 Av.</address>
</contact>

JAXB Unmarshalling a List

I am having trouble unmarshalling a simple list of elements with JAXB. I have simplified my model further and still have a problem.
I have 2 element classes, a Classroom element and a Student element. I have modelled them in Java like below:
#XmlRootElement(name = "classroom", namespace = "http://www.info.com/school/model")
#XmlAccessorType(XmlAccessType.FIELD)
public class Classroom {
#XmlElementWrapper(name = "students")
#XmlElement(name = "student", type = Student.class)
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
private String name;
private String gender;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
When I try to unmarshal the classroom element, it is unable to unmarshal the list of students. For example the following code should print out to System out "Number of Pupils is: 2", yet when I run it I get "Number of Pupils is: 0".
Is someone able to point me in the right direction for configuring the JAXB annotations so that I can unmarshal this?
I have even added a toString methof call on the JAXB context and I can see that the Student class is listed as well.
public static void main(String[] args) {
SimpleJaxbTestForLists sjtfl = new SimpleJaxbTestForLists();
sjtfl.unmarshal("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><classroom xmlns=\"http://www.info.com/school/model\"><students><student><name>Test Student 1</name><gender>Male</gender><age>12</age></student><student><name>Test Student 2</name><gender>Female</gender><age>12</age></student></students></classroom>");
}
public void unmarshal(String xmlContent) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Classroom.class);
System.out.println(jaxbContext.toString());
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(xmlContent);
Classroom classroom = (Classroom) jaxbUnmarshaller.unmarshal(reader);
System.out.println("Number of Pupils is: " + classroom.getStudents().size());
} catch (JAXBException ex) {
ex.printStackTrace();
}
}
Since your XML document specifies a default namespace, you can leverage a package level #XmlSchema annotation to map the namespace qualification:
package-info.java
#XmlSchema(
namespace = "http://www.info.com/school/model",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
You can read more about JAXB and namespace qualification on my blog:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html

Jackson JSON Deserialization with Root Element

I am having a question with Jackson that I think should be simple to solve, but it is killing me.
Let's say I have a java POJO class that looks like this (assume Getters and Setters for me):
class User {
private String name;
private Integer age;
}
And I want to deserialize JSON that looks like this into a User object:
{
"user":
{
"name":"Sam Smith",
"age":1
}
}
Jackson is giving me issues because the User is not the first-level object in the JSON. I could obviously make a UserWrapper class that has a single User object and then deserialize using that but I know there must be a more elegant solution.
How should I do this?
edit: this solution only works for jackson < 2.0
For your case there is a simple solution:
You need to annotate your model class with #JsonRootName(value = "user");
You need to configure your mapper with om.configure(Feature.UNWRAP_ROOT_VALUE, true); (as for 1.9) and om.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true); (for version 2).
That's it!
#JsonRootName(value = "user")
public static class User {
private String name;
private Integer age;
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(final Integer age) {
this.age = age;
}
#Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
ObjectMapper om = new ObjectMapper();
om.configure(Feature.UNWRAP_ROOT_VALUE, true);
System.out.println(om.readValue("{ \"user\": { \"name\":\"Sam Smith\", \"age\":1 }}", User.class));
this will print:
User [name=Sam Smith, age=1]

JAXB : 2 counts of IllegalAnnotationExceptions

This is my Parser class
public class Test {
public static void main(String args[]) throws Exception {
File file = new File("D:\\Test.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(MyOrder.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
MyOrder customer = (MyOrder) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer.getOrder().getSide());
}
}
This is MyOrder.java file
#XmlRootElement(name = "BXML")
public class MyOrder {
#XmlElement(name = "Bag")
protected Order order;
public MyOrder() {
}
#XmlAttribute
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
This is my Domain Object (Order.java )
#XmlRootElement(name = "BXML")
public class Order {
public Order() {
}
#XmlAttribute(name = "Side")
protected BigInteger Side;
#XmlValue
public BigInteger getSide() {
return Side;
}
public void setSide(BigInteger side) {
Side = side;
}
}
This is the exception that I am getting when I tried to run the program
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
#XmlAttribute/#XmlValue need to reference a Java type that maps to text in XML.
this problem is related to the following location:
at public com.Order com.MyOrder.getOrder()
at com.MyOrder
Class has two properties of the same name "order"
this problem is related to the following location:
at public com.Order com.MyOrder.getOrder()
at com.MyOrder
this problem is related to the following location:
at protected com.Order com.MyOrder.order
at com.MyOrder
For the #XmlAttribute/#XmlValue need to reference a Java type that maps to text in XML. issue you need to change your initialization of JAXBContext to the following:
JAXBContext jaxbContext = JAXBContext.newInstance(MyOrder.class, Order.class);
For the Class has two properties of the same name "order" issue, you need to change the definition of protected Order order; to private Order order;.
Also, you want to change the #XmlRootElement(name = "BXML") of your Order class to #XmlRootElement(name = "Order").
You can see the below sample code to generate Java Object from given XML.It is working fine in my system.
customer.xml
<?xml version="1.0" encoding="UTF-8"?>
<company>
<customer id="100">
<age>25</age>
<name>Ram</name>
<Address>
<city>Bangalore</city>
<country>India</country>
</Address>
<Address>
<city>Patna</city>
<country>India</country>
</Address>
</customer>
<customer id="200">
<age>26</age>
<name>Ashu</name>
<Address>
<city>Delhi</city>
<country>India</country>
</Address>
<Address>
<city>Madhubani</city>
<country>India</country>
</Address>
</customer>
</company>
Company.java
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;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="company")
public class Company {
#XmlElement(name="customer")
private List<Costumer> custList;
//
public List<Costumer> getCustList() {
return custList;
}
public void setCustList(List<Costumer> custList) {
this.custList = custList;
}
//
#Override
public String toString() {
return "Company [custList=" + custList + "]";
}
}
Costumer.java
#XmlAccessorType(XmlAccessType.FIELD)
class Costumer {
#XmlElement(name="name")
private String name;
#XmlElement(name="age")
private int age;
#XmlElement(name="id")
private int id;
#XmlElement(name="Address")
private List<Address> addressList;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<Address> getAddressList() {
return addressList;
}
public void setAddressList(List<Address> addressList) {
this.addressList = addressList;
}
#Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + ", id=" + id + ", addressList=" + addressList + "]";
}
}
Address.java
#XmlAccessorType(XmlAccessType.FIELD)
class Address {
#XmlElement(name="city")
private String city;
#XmlElement(name="country")
private String country;
//
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
//
#Override
public String toString() {
return "Address [city=" + city + ", country=" + country + "]";
}
}
TestMain.java
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class TestMain {
public static void main(String[] args) {
String xmlPath = "C:\\" + File.separator + "customer.xml";
try {
File file = new File(xmlPath);
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] {Company.class,Address.class,Costumer.class});
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Company customer = (Company) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Outout:
Company [custList=[Customer [name=Ram, age=25, id=0, addressList=[Address [city=Bangalore, country=India], Address [city=Patna, country=India]]], Customer [name=Ashu, age=26, id=0, addressList=[Address [city=Delhi, country=India], Address [city=Madhubani, country=India]]]]]
This is because the sub-elements of that class you are creating JAXBcontext instance ,doesn't have the same name as of the element names defined inside it.
Example:
#XmlType(name = "xyz", propOrder = { "a", "b", "c", "d" })
#XmlRootElement(name = "testClass")
public class TestClass
{
#XmlElement(required = true)
protected Status status;
#XmlElement(required = true)
protected String mno;
#XmlElement(required = true)
}
In the above class you don't have "xyz" , but if you will put the property name that is not available JAXBContext instantiation throws IlligalAnnotationException.
If anyone is curious about the usage of JAXB and Lombok.
My fix was to remove the getter and setter from the root object.

Categories

Resources