How can I create Generics for XML Parsing? - java

I currently using jsoup and sometimes dom4j for parsing string of xml.
Here's an example on how I do it using jsoup.
Document doc = Jsoup.parse(xml);
Elements root = doc.select("person");
for(Elements elem : elements){
Person person = new Person();
person.setFirstname(elem.select("firstName").text());
person.setLastname(elem.select("lastName").text());
person.setAddress(elem.select("address").text());
//other setters here
}
Everytime I have to parse xml I have to get all elements and set to setters of POJO. Now I want to create a Generics where I only have to do is to passed a string of xml and a class of POJO then it will set all the values of fields based on all the elements of xml. How can I do it? Any ideas?
Thanks in advance.

JAXB is the way to go.
Note:
It is included in JAVA 1.6 and later versions
Add XML tags to your POJO (XmlRootElement is enough for simple objects, XmlElement can also be added to variables)
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Person")
public class Person {
private String firstName;
private String lastName;
private String address;
public final String getFirstName() {
return firstName;
}
public final void setFirstName(String firstName) {
this.firstName = firstName;
}
public final String getLastName() {
return lastName;
}
public final void setLastName(String lastName) {
this.lastName = lastName;
}
public final String getAddress() {
return address;
}
public final void setAddress(String address) {
this.address = address;
}
#Override
public String toString() {
return "FirstName: " + firstName + " LastName: " + lastName + " Address: " + address;
}
}
Use Unmarshaller to create the POJO from the xml file.
File file = new File("<Path to Xml file>");
JAXBContext context = JAXBContext.newInstance(Person.class);
Unmarshaller unmarsheller = context.createUnmarshaller();
Person person = (Person) unmarsheller.unmarshal(file);
System.out.println(person);
You can use Marshaller to create the XML from the POJO also.
There are more examples available here to create complex objects, add lists, arrays.
Note: It is not available in Android Platform, If you want to use it on android you can use SimpleXML with almost same implementation

Related

JSON String to Java object with JSON string key rename [duplicate]

This question already has answers here:
Different names of JSON property during serialization and deserialization
(14 answers)
Closed 1 year ago.
I have the following requirement for JSON string conversion to Java Object.
class Person {
private String firstName;
private String lastName;
}
ObjectMapper MAPPER = new ObjectMapper();
String jsonString = "{\"FST_NME\":\"stack\",\"LST_NME\":\"OVERFLOW\"}";
Person person = MAPPER.readValue(jsonString, Person.class);
The above conversion returns null as the Person class attribute name doesn't match.
With #JsonProperty it converts correctly, but the final JSON result key is the same key as in jsonString.
{
"FST_NME" : "stack",
"LST_NME" : "overflow"
}
but I am looking for something like below.
{
"firstName" : "stack",
"lastName" : "overflow"
}
I tried renaming the key in jsonString and it works as expected.
But can we achieve the above result using any annotations or any other approach?
Thanks.
You just need to add #JsonProperty in both setter and getters.
In your case,
You are reading JSON string key FST_NME, so you need to add #JsonProperty('FST_NME') in the setter method for firstName and as you want to get the final JSON string with key firstName so you need to add #JsonProperty('firstName') in the getter method of firstName.
And same for lastName.
Following is the working code.
package com.ubaid.stackoverflow;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
#Slf4j
public class Saravanan {
#SneakyThrows
public static void main(String[] args) {
ObjectMapper MAPPER = new ObjectMapper();
String jsonString = "{\"FST_NME\":\"stack\",\"LST_NME\":\"OVERFLOW\"}";
Person person = MAPPER.readValue(jsonString, Person.class);
String finalJson = MAPPER.writeValueAsString(person);
log.debug("Final JSON: {}", finalJson);
}
}
class Person {
private String firstName;
private String lastName;
#JsonProperty("firstName")
public String getFirstName() {
return firstName;
}
#JsonProperty("FST_NME")
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#JsonProperty("lastName")
public String getLastName() {
return lastName;
}
#JsonProperty("LST_NME")
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
The output of above code is:
Final JSON: {"firstName":"stack","lastName":"OVERFLOW"}
Add below annotation on gets methods.
#JsonGetter("FST_NME")
public String getFirstName(){
return first Name;
}
Read data to a DTO class (Person DTO) with #JsonProperty
Class Person as you wish
Convert DTO to Person
class PersonDTO {
#JsonProperty(value = "FST_NME")
private String firstName;
#JsonProperty(value = "LST_NME")
private String lastName;
}
class Person {
private String firstName;
private String lastName;
}
ObjectMapper MAPPER = new ObjectMapper();
String jsonString = "{\"FST_NME\":\"stack\",\"LST_NME\":\"OVERFLOW\"}";
PersonDTO persondto = MAPPER.readValue(jsonString, PersonDTO.class);
Person person = new Person();
person.setFirstName(persondto.getFirstName());
person.setLastName(persondto.getLastName());

How to POST a document with manual id in MongoDB database from Spring hypermedia-based RESTful front end?

I am following this spring guide:
https://spring.io/guides/gs/accessing-mongodb-data-rest/
Everything is perfect, however if I want to POST a document with manual id, I am not able to do that.
Here is what all I have done:
I inserted one document from Mongo shell by the command db.person.insert({"_id": "111111", "firstName" : "Vikas", "lastName" : "Prasad"});
This works fine and if I do a GET at http://localhost:8080/people from Postman, I can see the person document with id 111111 in the response having self href as http://localhost:8080/people/111111
But if I am sending a POST request from Postman at http://localhost:8080/people with body as {"_id": "222222", "firstName" : "Aadish", "lastName" : "Patodi"}, the document is getting inserted with an auto id instead of 222222. Because of which obviously I cant access this docuemnt by doing a GET at http://localhost:8080/people/222222 unlike the case when I used insert() from the shell to insert a document with manual id. Instead I have to hit a GET at http://localhost:8080/people/57bc29ada3fab115cc9b546b to fetch this second document.
Just to check if I am POSTing the {"_id": "222222", "firstName" : "Aadish", "lastName" : "Patodi"} again, its getting inserted again at a new auto generated id: http://localhost:8080/people/57bc2bdaa3fab115cc9b546c. It means MongoDB is not even looking at the _id, else it must have thrown duplicate key error.
I tried searching various sources. All I can found is an implementation of the data access code separately in JAVA at back end and calling respective MongoDB methods.
My question is:
Just like in the given tutorial they are performing every operation without defining any JAVA back end code for data access from MongoDB for auto id documents, is there a way to do the same for manual id documents?
Or just for this one use case I have to implement the data access code at the back end?
I am using CorsFilter to handle cross origin requests.
Edit:
Below is the Person class:
package hello;
import org.springframework.data.annotation.Id;
public class Person {
#Id private String id;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
I have tried:
-> adding getter and setter for id attribute
-> renaming id to employeeNumber
-> renaming id to employeeNumber and adding getter and setter for employeeNumber
None of the above three solved the issue.
as discussed on the comment, looks like your _id field is not mapped correctly. Can you check if the _id is mapped correctly in the pojo ?
Finally, I got it working by renaming id with _id and adding getter and setter for the same in the Person class.
package hello;
import org.springframework.data.annotation.Id;
public class Person {
#Id private String _id;
private String firstName;
private String lastName;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}

Spring JSON request body not mapped to Java POJO

I'm using Spring to implement a RESTful web service. One of the endpoints takes in a JSON string as request body and I wish to map it to a POJO. However, it seems right now that the passed-in JSON string is not property mapped to the POJO.
here's the #RestController interface
#RequestMapping(value="/send", headers="Accept=application/json", method=RequestMethod.POST)
public void sendEmails(#RequestBody CustomerInfo customerInfo);
the data model
public class CustomerInfo {
private String firstname;
private String lastname;
public CustomerInfo() {
this.firstname = "first";
this.lastname = "last";
}
public CustomerInfo(String firstname, String lastname)
{
this.firstname = firstname;
this.lastname = lastname;
}
public String getFirstname(){
return firstname;
}
public void setFirstname(String firstname){
this.firstname = firstname;
}
public String getLastname(){
return lastname;
}
public void getLastname(String lastname){
this.lastname = lastname;
}
}
And finally my POST request:
{"CustomerInfo":{"firstname":"xyz","lastname":"XYZ"}}
with Content-Type specified to be application/json
However, when I print out the object value, the default value("first" and "last") got printed out instead of the value I passed in("xyz" and "XYZ")
Does anyone know why I am not getting the result I expected?
FIX
So it turned out that, the value of request body is not passed in because I need to have the #RequestBody annotation not only in my interface, but in the actual method implementation. Once I have that, the problem is solved.
So it turned out that, the value of request body is not passed in because I need to have the #RequestBody annotation not only in my interface, but in the actual method implementation. Once I have that, the problem is solved.
You can do it in many ways, Here i am going to do it in below different ways-
NOTE: request data shuld be {"customerInfo":{"firstname":"xyz","lastname":"XYZ"}}
1st way We can bind above data to the map as below
#RequestMapping(value = "/send", headers = "Accept=application/json", method = RequestMethod.POST)
public void sendEmails(#RequestBody HashMap<String, HashMap<String, String>> requestData) {
HashMap<String, String> customerInfo = requestData.get("customerInfo");
String firstname = customerInfo.get("firstname");
String lastname = customerInfo.get("lastname");
//TODO now do whatever you want to do.
}
2nd way we can bind it directly to pojo
step 1 create dto class UserInfo.java
public class UserInfo {
private CustomerInfo customerInfo1;
public CustomerInfo getCustomerInfo1() {
return customerInfo1;
}
public void setCustomerInfo1(CustomerInfo customerInfo1) {
this.customerInfo1 = customerInfo1;
}
}
step 1. create another dto classCustomerInfo.java
class CustomerInfo {
private String firstname;
private String lastname;
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}
step 3 bind request body data to pojo
#RequestMapping(value = "/send", headers = "Accept=application/json", method = RequestMethod.POST)
public void sendEmails(#RequestBody UserInfo userInfo) {
//TODO now do whatever want to do with dto object
}
I hope it will be help you out. Thanks
The formatting on this is terrible, but this should work for jackson configuration.
<!-- Use Jackson for JSON conversion (POJO to JSON outbound). -->
<bean id="jsonMessageConverter"
class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
<!-- Use JSON conversion for messages -->
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="jsonMessageConverter"/>
</list>
</property>
</bean>
ALso, as mentioned in a comment, your JSON is wrong for your object.
{"firstname":"xyz",‌​"lastname":"XYZ"}
does appear to be the correct JSON for your object.
Sample Data :
[
{
"targetObj":{
"userId":1,
"userName":"Devendra"
}
},
{
"targetObj":{
"userId":2,
"userName":"Ibrahim"
}
},
{
"targetObj":{
"userId":3,
"userName":"Suraj"
}
}
]
For above data this pring controller method working for me:
#RequestMapping(value="/saveWorkflowUser", method = RequestMethod.POST)
public void saveWorkflowUser (#RequestBody List<HashMap<String ,HashMap<String ,
String>>> userList ) {
System.out.println(" in saveWorkflowUser : "+userList);
//TODO now do whatever you want to do.
}
remove those two statements from default constructor and try

XStream don't convert a xml tag

I have an xml. I want to convert to object , xstream convert well all tags except one of them it gives null.
Any idea about this problem ?
xml:
<person>
<name>nnn</name>
<age>aaa</age>
<address>
<city>ccc</city>
<countryco</country>
</address>
</person>
Code java
XStream _xstream = new XStream();
_xstream.setMode(XStream.NO_REFERENCES);
_xstream.aliasType("person", PersonType.class);
_xstream.aliasType("address", PersonType.class);
_xstream.aliasField("city", AddressType.class, "city");
_xstream.aliasField("country", AddressType.class, "country");
When I inspect the object person , all variables are ok , but address is always null
i tried this :
_xstream.aliasType("person", PersonType.class);
_xstream.aliasType("address", AddressType.class);
_xstream.aliasField("city", AddressType.class, "city");
_xstream.aliasField("country", AddressType.class, "country");
but still don't work !
In this case the usage of alias are redundant. XStream will convert the names of the fields automaticly.
How ever you adress seems to be an nested type. You are using the same type for two aliases:
_xstream.aliasType("person", PersonType.class);
_xstream.aliasType("address", PersonType.class);
it should be
_xstream.aliasType("address", AddressType.class);
for adress alias.
Java Code:
#XStreamAlias("person")
public class Person {
#XStreamAlias("name")
private String Name;
#XStreamAlias("age")
private long Age;
#XStreamImplicit(itemFieldName = "address")
private List addresses = new ArrayList();
}
#XStreamAlias("adress")
public class Address{
#XStreamAlias("city")
private String City;
#XStreamAlias("country")
private String Country;
}
Main Code:
FileReader reader = new FileReader("file.xml"); // load file
XStream xstream = new XStream();
xstream.processAnnotations(Person.class);
xstream.processAnnotations(Address.class);
Person person = (Person) xstream.fromXML(reader);
I believe address would be a reference of object Address in your class Person. If so then you need to do like this:
Person.java
public class Person{
private String name;
private int age;
private Address address;
public String getName(){
return name;
}
public int getAge(){
return age;}
public String getcity(){
return address.getCity();
}
public String getCountry(){
return address.getCountry();
}
}
Address.java
public class Address {
private String city;
private String country;
public String getCity(){
return city;
}
public String getCountry(){
return country;
}
}
JAVA CODE
FileReader xmlReader = new FileReader("file.xml"); // load file
XStream stream = new XStream(new StaxDriver());
stream.alias("person",Person.class);//Since in your xml file `person` is tag
Person person = (Person) stream.fromXML(xmlReader);
System.out.println("Name:"+person.getName()+"\nAge:"+person.getAge()+
"\nCity:"+person.getCity()+"\nCountry:"+person.getCountry();

How to create DTO class

I want to create DTO class for User. my input to program is
firstname, lastname,lastname.role,group1,group2,group3.
so for each user role consist of group_1,group_2,group_3.....
In database i want to store in following format
demo,demo,demo,roleId, gorup_1_name group_1_Id
demo,demo,demo,roleId, gorup_2 and group_2_Id
demo,demo,demo,roleId, gorup_3 and group_3_Id
I was able separate all this things , but i want to assign this value to userDTO class and stored into database. basically im new to core java part. so how can create structure for this?
A Data Transfer Object (DTO) class is a java-bean like artifact that holds the data that you want to share between layer in your SW architecture.
For your usecase, it should look more or less like this:
public class UserDTO {
String firstName;
String lastName;
List<String> groups;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public List<String> getGroups() {
return groups;
}
public void setGroups(List<String> groups) {
this.groups = groups;
}
// Depending on your needs, you could opt for finer-grained access to the group list
}
One thing to add:
The essence of a DTO is that it transfers data across the wire. So it will need to be Serializable.
http://martinfowler.com/eaaCatalog/dataTransferObject.html

Categories

Resources