Creating JSON using Jackson - java

I have a List<Person> list.
I want to serialize it to JSON with some other attributes, using Jackson Api.
The output should be like this:
{
"sEcho": 3,
"iTotalRecords": 10,
"iTotalDisplayRecords": 10,
"aaData": [ <--here's the persons
{
"name": "TestName1",
"status": "ok"
},
{
"name": "TestName2",
"status": "ok"
},
...
]
}
Probably very simple but couldn't figure it from Jackson's Api.
Thanks

I'd create a new class called PersonGroup having any of the extra fields you need with the List as another field on this class - for the example you gave this field would be named aaData.
This would represent the structure you have here. If you think a new class is too much then you could just make a HashMap of Objects and store the extra fields as whatever object you like and then add these to the HashMap, making sure the keys match the name of the extra fields and making sure your List is also in the HashMap.
Deserializing this class or HashMap should return the output you mentioned.

Try with this.
Hope it would help.
import java.util.ArrayList;
import java.util.List;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
public class JsonSimpleExample {
public static void main(String[] args) {
List<Person> personList = new ArrayList<Person>();
for(int i=0 ;i< 5;i ++) {
Person person = new Person("TestName" + (i+1), "OK");
personList.add(person);
}
JSONObject obj = new JSONObject();
obj.put("sEcho", 3);
obj.put("iTotalRecords", 10);
obj.put("iTotalDisplayRecords", 10);
JSONArray list = new JSONArray();
for (Person person : personList) {
JSONObject innerObj = new JSONObject();
innerObj.put("name",person.getName());
innerObj.put("status",person.getStatus());
list.add(innerObj);
}
obj.put("aaData", list);
System.out.print(obj);
}
}
class Person {
private String name;
private String status;
public Person(String name, String status) {
this.name = name;
this.status = status;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

Related

How to keep the JSON's order preserved while sending to frontend application from SpringBoot Application's service?

I'm developing a springboot application.
I've a class with the following fields
class MyClass
{
String s1;
String s2;
String s3;
String s4;
//getters setters constructors
}
I'm calling an API which in turn calls a service.
public String myService()
{
JSONArray arr1 = new JSONArray();
for (Items item : itemsList)
{
JSONObject itemObj = new JSONObject();
itemObj.put("s1","Value1");
itemObj.put("s2","Value2");
itemObj.put("s3","Value3")
itemObj.put("s4","Value4");
arr1.put(itemObj);
}
JSONObject out = new JSONObject();
out.put("total_Items", arr1);
return out.toString(); // this is org.json.JSONObject
}
This way I'm able to get the excel with the reordered members as the columns when a button is clicked at the frontend angular app.
What I want is the order of the the members in the columns remains preserved when exporting into an excel sheet.
s1|s2|s3|s4 //as per the above example
I've many other services as well, which return different types of Objects(apart from the MyClass mentioned here) so I wanted to return the elements in the order defined (as per the order of members in the class) from the backend itself.
I know that JSON does not allow us to preserve the order as it internally uses a HASHMAP.
Is there a way to return a JSON response such that the order remains same as that of the class members?
I also tried using GSON in the below way.
public String myService()
{
MyClass itemsArray[] = new MyClass[itemsList.size()];
int i=0;
for (Items item : itemsList)
{
MyClass itemObj = new MyClass();
itemObj.setS1("Value1");
itemObj.setS2("Value2");
itemObj.setS3("Value3")
itemObj.setS4("Value4");
itemsArray[i]=itemObj;
}
Gson gson = new Gson();
return gson.toJson(itemsArray); // this is java.lang.String
}
In this scenario I'm able to get the API response(on POSTMAN) with the elements in ordered fashion but when exporting on the frontend angular app it freezes at the downloading screen.
I tried doing conversion to JSONObject and other things randomly but was not able to make the code work properly.
Is there anyway the problem can be resolved at the backend...or something needs to be done at the frontend only?
Thanks in advance.
If you want to do using DataStructure use LinkedHashMap as given below. It will serialize in inserted order.
public static void main(String args[]){
ObjectMapper mapper = new ObjectMapper();
Map<String, String> itemObj = new LinkedHashMap<>();
itemObj.put("s91","Value1");
itemObj.put("s2","Value2");
itemObj.put("s3","Value3");
itemObj.put("s4","Value4");
try {
String jsonString = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(itemObj);
System.out.println(jsonString);
}
catch (IOException e) {
e.printStackTrace();
}
}
{
"s91" : "Value1",
"s2" : "Value2",
"s3" : "Value3",
"s4" : "Value4"
}
If you want to serialize in sorted order the use TreeMap, it will serialize in sorted key
Map<String, String> itemObj = new TreeMap<>();
...
{
"s2" : "Value2",
"s3" : "Value3",
"s4" : "Value4",
"s91" : "Value1"
}
This can be done using Jackson library using the #JsonPropertyOrder annotation.
You can define the order of elements as given below above class
#JsonPropertyOrder({ "s3", "s2", "s1", "s4"})
Refer to below a working example
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.sun.istack.NotNull;
import java.io.IOException;
import java.util.UUID;
#JsonPropertyOrder({ "id", "password", "name", "email", "enabled" })
public class UserResource {
private UUID id;
#NotNull
private String name;
#NotNull
private String email;
private boolean enabled;
private String password;
public UserResource(UUID id, String name, String email, boolean enabled, String password) {
this.id = id;
this.name = name;
this.email = email;
this.enabled = enabled;
this.password = password;
}
public UUID getId() {
return id;
}
public void setId(UUID id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public static void main(String args[]){
ObjectMapper mapper = new ObjectMapper();
try {
UserResource student = new UserResource(UUID.randomUUID(), "sheel", "sheel#c4c.com",true, "$$$$$$%%##^^$DSGHHH");
String jsonString = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(student);
System.out.println(jsonString);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
and output as given below
{
"id" : "fbfcd21d-731e-4acb-9fec-90a499e47cc9",
"password" : "$$$$$$%%##^^$DSGHHH",
"name" : "sheel",
"email" : "sheel#c4c.com",
"enabled" : true
}

Is there a way to unmarshall an array inside an object directly into a list using Jackson

I have a very simple JSON:
{
"fruits": [
{
"id": 100,
"name": "Banana"
},
{
"id": 101,
"name": "Apple"
}
]
}
I can unmarshall this JSON easily using the default ObjectMapper that comes with Java and two simple POJO classes which look like this:
public class FruitList {
private List<Fruit> fruits;
public List<Fruit> getFruits() {
return fruits;
}
public void setFruits(List<Fruit> fruits) {
this.fruits = fruits;
}
}
And the individual Fruit elements:
public class Fruit {
private String name;
private int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
This works and is perfectly acceptable. However, I would like to know it it is possible to unmarshal this JSON directly into a List<Fruit> - somehow ignoring the container object called fruits?
I tried using this feature but it did not work:
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
Also experimenting with:
List<Fruit> list = mapper.readValue(jsonString,
TypeFactory.defaultInstance().constructCollectionType(List.class, Fruit.class));
Did not do the trick.
Thanks for any help,
Cheers

Parsing JSON data into model objects in Java

I haven't worked with JSON data before, thus the question.
I've the following JSON object in a file.
{
"courses": [
{ "id":998", "name":"Java Data Structures", "teacherId":"375" },
{ "id":"999", "name":"Java Generics", "teacherId":"376" }
],
"teachers": [
{ "id":"375", "firstName":"Amiyo", "lastName":"Bagchi"},
{ "id":"376", "firstName":"Dennis", "lastName":"Ritchie"}
]
}
Here are my model Objects.
public class Course {
private int _id;
private String _name;
private Teacher _teacher;
}
public class Teacher {
private int _id;
private String _firstName;
private String _lastName;
}
My task is to read the JSON Objects and return a list of Model objects.
I've imported the simple.JSON family of jar and here's my code that reads the file.
FileReader reader = new FileReader(path);
JSONParser parser = new JSONParser();
Object obj = parser.parse(reader);
JSONObject jsonObject = (JSONObject) obj;
My question is,
How do I parse the JSON document into my Model objects?
If the input file is JSON but of a different format how do I throw exception/handle the anomaly?
Any help appreciated.
UPDATE I suggest you use JSON parser to parse the data:
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
class Course {
public int _id;
public String _name;
public Teacher _teacher;
private Course(int id, String name, Teacher teacher){
this._id = id;
this._name = name;
this._teacher = teacher;
}
public Course() {
}
}
class Teacher {
public int _id;
public String _firstName;
public String _lastName;
private Teacher(int id, String fname, String lname){
this._id = id;
this._firstName = fname;
this._lastName = lname;
}
public Teacher(){
}
}
public class jsontest {
public static void main(String[] args) throws JSONException, IOException {
// String JSON_DATA = "{\n"+
// " \"courses\": [\n"+
// " { \"id\":\"998\", \"name\":\"Java Data Structures\", \"teacherId\":\"375\" },\n"+
// " { \"id\":\"999\", \"name\":\"Java Generics\", \"teacherId\":\"376\" }\n"+
// "\n"+
// " ],\n"+
// " \"teachers\": [\n"+
// " { \"id\":\"375\", \"firstName\":\"Amiyo\", \"lastName\":\"Bagchi\"},\n"+
// " { \"id\":\"376\", \"firstName\":\"Dennis\", \"lastName\":\"Ritchie\"} \n"+
// " ]\n"+
// "}\n"+
// "";
// read json file into string
String JSON_DATA = new String(Files.readAllBytes(Paths.get("path_to_json_file")), StandardCharsets.UTF_8);
// using a JSON parser
JSONObject obj = new JSONObject(JSON_DATA);
// parse "teachers" first
List<Teacher> listCourses = new ArrayList<Teacher>();
List<JSONObject> listObjs = parseJsonData(obj,"teachers");
for (JSONObject c: listObjs) {
Teacher teacher = new Teacher();
teacher._id = c.getInt("id");
teacher._firstName = c.getString("firstName");
teacher._lastName = c.getString("lastName");
listCourses.add(teacher);
}
// parse "courses" next
List<Course> resultCourses = new ArrayList<Course>();
List<JSONObject> listObjs2 = parseJsonData(obj, "courses");
for (JSONObject c: listObjs2) {
Course course = new Course();
course._id = c.getInt("id");
course._name = c.getString("name");
int teacherId = c.getInt("teacherId");
HashMap<String, Teacher> map = new HashMap<String, Teacher>();
for (Teacher t: listCourses){
map.put(Integer.toString(t._id), t);
}
course._teacher = map.get(Integer.toString(teacherId));
resultCourses.add(course);
}
}
public static List<JSONObject> parseJsonData(JSONObject obj, String pattern)throws JSONException {
List<JSONObject> listObjs = new ArrayList<JSONObject>();
JSONArray geodata = obj.getJSONArray (pattern);
for (int i = 0; i < geodata.length(); ++i) {
final JSONObject site = geodata.getJSONObject(i);
listObjs.add(site);
}
return listObjs;
}
}
Output:
BTW: The json data in the example has one value whose double quotes are not in pairs. To proceed, it must be fixed.
You should try using Jackson as the JSON parsing library instead. There is a lot more support and features that come with it.
In your case, a couple of annotations to map the JSON properties to the Java fields should be sufficient.
https://github.com/FasterXML/jackson-annotations
https://github.com/FasterXML/jackson-databind
UPDATE: Some code, to show just much better this can be done with Jackson.
public class Course {
#JsonProperty("id")
private int _id;
#JsonProperty("name")
private String _name;
#JsonProperty("teacher")
private Teacher _teacher;
// ...public getters and setters
}
public class Teacher {
#JsonProperty("id")
private int _id;
#JsonProperty("firstName")
private String _firstName;
#JsonProperty("lastName")
private String _lastName;
// ...public getters and setters
}
// Container class to conform to JSON structure
public class CoursesDto {
private List<Teacher> teachers;
private List<Course> courses;
}
// In your parser place
ObjectMapper mapper = new ObjectMapper();
FileReader reader = new FileReader(path);
CoursesDto dto = mapper.readValue(reader, CoursesDto.class);
The #JsonProperty annotations tell Jackson what JSON key should be used to deserialize. They are not necessary if the property names match the JSON keys. That means that if you remove the leading underscore from your property names, this would work without annotations. Also, Jackson will default to using public fields and getter/setter methods. This means that you can keep your fields prefixed by _ as long as the getter/setter don't have it (setFirstName(String firstName)).

Custom object display in JSON

I'm using only jersey and not jackson to create a REST api. I've two model objects,
public class Course {
private int id;
private String name;
private Teacher teacher;
}
public class Teacher {
private int id;
private String givenName;
private String familyName;
}
I'm creating a service and returning a List of Course objects,
public List<Course> getAll(){
return db.getCourseList();
}
The display is as expected,
[{"id":101,"name":"Introduction to Java","teacher":{"familyName":"Bar","givenName":"Foo","id":201}},{"id":102,"name":"Intermediate Java","teacher":{"familyName":"Prank","givenName":"Foo","id":202}}]
Now I want to customize my JSON object to display in the following format, with only the teacher ID.
[{"id":"100","name":"Introduction to Java","teacherId":"201"},{"id":"101","name":"Intermediate Java","teacherId":"201"}
So this is the view model that I designed.
#XmlRootElement
public class CourseTeacherIdView {
private int id;
private String name;
private int teacherId;
CourseTeacherIdView(){
}
public CourseTeacherIdView(int id, String name, int teacherId){
this.id = id;
this.name = name;
this.teacherId = teacherId;
}
}
And I use this method to return the List of view objects.
public List<CourseTeacherIdView> getAll(){
List<Course> list = db.getCourseList();
List<CourseTeacherIdView> viewList = new ArrayList<>();
for(Iterator<Course> itr = list.iterator(); itr.hasNext();){
Course c = (Course) itr.next();
viewList.add(new CourseTeacherIdView(c.getId(), c.getName(), c.getTeacher().getId()));
}
return viewList;
}
This is the result that I get.
[{},{},{}]
What am I doing wrong.
You can achieve that with Jackson and creating a custom serializer like the following:
public class CourseSerializer extends JsonSerializer<Course> {
#Override
public void serialize(Course value,
JsonGenerator gen,
SerializerProvider serializers) throws IOException {
gen.writeStartObject();
Field[] fields = value.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
try {
Object obj = field.get(value);
if (obj instanceof Teacher) {
Teacher teacher = (Teacher) obj;
gen.writeStringField("teacherId", String.valueOf(teacher.getId()));
} else {
gen.writeStringField(field.getName(), obj.toString());
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
gen.writeEndObject();
}
}
Test case:
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Course.class, new CourseSerializer());
mapper.registerModule(module);
Teacher teacher1 = new Teacher(123, "teacher1", "surename1");
Teacher teacher2 = new Teacher(234, "teacher2", "surename2");
Course course1 = new Course(1, "course1", teacher1);
Course course2 = new Course(2, "course2", teacher2);
List<Course> courses = Arrays.asList(new Course[]{course1, course2});
String serialized = mapper.writeValueAsString(courses);
}
Output:
[{
"id": "1",
"name": "course1",
"teacherId": "123"
}, {
"id": "2",
"name": "course2",
"teacherId": "234"
}]
If I understood you correctly you could either create new view model representation with only the id and map each object in the list to it, or use #jsonignore on not relevant fields (if jersey is using Jackson). Or even retrieve only the ids from the db. Depends on use case.

How to implement customized serialization feature in fasterxml

My JSON:
{
"name": "asdf",
"age": "15",
"address": {
"street": "asdf"
}
}
If street is null, with JsonSerialize.Inclusion.NON_NULL, I can get..
{
"name": "asdf",
"age": "15",
"address": {}
}
But I want to get something like this.. (when address is not null, it is a new/empty object. But street is null.)
{
"name": "asdf",
"age": "15"
}
I thought to have custom serialization feature like JsonSerialize.Inclusion.VALID_OBJECT.
Adding isValid() method in the Address class then if that returns true serialize else don't serialize.
But I don't know how to proceed further/which class to override. Is this possible or any other views on this? Please suggest.
Added classes
public static void main(String[] args) {
ObjectMapper mapper = new ObjectMapper();
Customer customer = new Customer();
customer.setName("name");
customer.setAddress(new Address());
mapper.writeValue(new File("d:\\customer.json"), customer);
}
#JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class Customer {
private String name;
private Address address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
#JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
public class Address {
private String street;
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
Note: I am not worrying about deserialization now. i.e, loss of address object.
Thanks in advance.
Customized JSON Object using Serialization is Very Simple.
I have wrote a claas in my project i am giving u a clue that how to Implement this in Projects
Loan Application (POJO Class)
import java.io.Serializable;
import java.util.List;
import org.webservice.business.serializer.LoanApplicationSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
#JsonSerialize(using=LoanApplicationSerializer.class)
public class LoanApplication implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private double amount;
private User borrowerId;
private String businessType;
private String currency;
private int duration;
private Date lastChangeDate;
private long loanApplicationId;
private String myStory;
private String productCategory;
private String purpose;
private Date startDate;
private String status;
private String type;
private String salesRepresentative;
Now LoanApplicationSerializer class that contains the Customization using Serialization Logic................
package org.ovamba.business.serializer;
import java.io.IOException;
import org.webservice.business.dto.LoanApplication;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
public class LoanApplicationSerializer extends JsonSerializer<LoanApplication> {
#Override
public void serialize(LoanApplication prm_objObjectToSerialize, JsonGenerator prm_objJsonGenerator, SerializerProvider prm_objSerializerProvider) throws IOException, JsonProcessingException {
if (null == prm_objObjectToSerialize) {
} else {
try {
prm_objJsonGenerator.writeStartObject();
prm_objJsonGenerator.writeNumberField("applicationId", prm_objObjectToSerialize.getLoanApplicationId());
prm_objJsonGenerator.writeStringField("status", prm_objObjectToSerialize.getStatus());
prm_objJsonGenerator.writeNumberField("amount", prm_objObjectToSerialize.getAmount());
prm_objJsonGenerator.writeNumberField("startdate", prm_objObjectToSerialize.getStartDate().getTime());
prm_objJsonGenerator.writeNumberField("duration", prm_objObjectToSerialize.getDuration());
prm_objJsonGenerator.writeStringField("businesstype", prm_objObjectToSerialize.getBusinessType());
prm_objJsonGenerator.writeStringField("currency", prm_objObjectToSerialize.getCurrency());
prm_objJsonGenerator.writeStringField("productcategory", prm_objObjectToSerialize.getProductCategory());
prm_objJsonGenerator.writeStringField("purpose", prm_objObjectToSerialize.getPurpose());
prm_objJsonGenerator.writeStringField("mystory", prm_objObjectToSerialize.getMyStory());
prm_objJsonGenerator.writeStringField("salesRepresentative", prm_objObjectToSerialize.getSalesRepresentative());
} catch (Exception v_exException) {
//ExceptionController.getInstance().error("Error while Serializing the Loan Application Object", v_exException);
} finally {
prm_objJsonGenerator.writeEndObject();
}
}
}
}
Hope This may help u alot. Thanks..
You can do it by annotating your class with #JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
Example:
#JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL)
public myClass{
// attributes and accessors
}
You can find some useful informations at Jackson faster xml

Categories

Resources