I have a file called persons.json:
[
{
"id": 1,
"name": "The Best",
"email": "thenextbigthing#gmail.com",
"birthDate": "1981-11-23"
},
{
"id": 2,
"name": "Andy Jr.",
"email": "usa#gmail.com",
"birthDate": "1982-12-01"
},
{
"id": 3,
"name": "JohnDoe",
"email": "gameover#gmail.com",
"birthDate": "1990-01-02"
},
{
"id": 4,
"name": "SomeOne",
"email": "rucksack#gmail.com",
"birthDate": "1988-01-22"
},
{
"id": 5,
"name": "Mr. Mxyzptlk",
"email": "bigman#hotmail.com",
"birthDate": "1977-08-12"
}
]
I'd like to parse this file into an ArrayList with FasterXML, possibly with it's ObjectMapper() function and then being able to access each value (id, name, etc.) individually as a String when iterating through the newly created ArrayList. How could I do that? I don't even know what kind of list I could/should use in order to get access to each value individually. I'm kind of stuck here. List<???>
First of all:
FasterXML uses Jackson underneath to parse/produce json.
Now: to use Jackson, first of all create a container object for the data of your json, which we will call Person
public class Person {
private int id;
private String name, email;
#JsonFormat
(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private Date birthDate;
//add here getters and setters ...
}
At this point, supposing you have pathToPersonsJsonFile as a string containing the path to your persons.json, you can use your file like this:
byte[] jsonData = Files.readAllBytes(Paths.get(pathToPersonsJsonFile));
ObjectMapper objectMapper = new ObjectMapper();
Person[] parsedAsArray = objectMapper.readValue(jsonData, Person[].class); //array
ArrayList<Persons> persons = new ArrayList<>(Arrays.asList(parsedAsArray)); //your list
Note: JsonFormat enables to declare which format that value has on your json.
First you should create POJO for storing info:
public class Person {
Long id;
String name;
String email;
#JsonFormat("yyyy-mm-dd")
Date birthDate;
...
}
next you should call:
List<Person> myObjects = new ObjectMapper().readValue(jsonInput, new TypeReference<List<Person>>(){});
This should be enough
ObjectMapper objectMapper = new ObjectMapper();
List<Person> list = objectMapper.readValue(new File("path_to_persons.json"), new TypeReference<List<Person>>(){});
public class Person {
private String id;
private String name;
private String email;
private String birthDate;
.....
}
1) First create class Person.java
2) Then read the persons.json file and create a JSONArray from it.
3) Then parse as given below:
class Person{
private int id;
private String name;
private String email;
private String birthDate;
public int getId() {
return id;
}
public void setId(int 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 String getBirthDate() {
return birthDate;
}
public void setBirthDate(String birthDate) {
this.birthDate = birthDate;
}
}
public List<Person> getPersonList(JSONArray dataArray){
List<Person> personList = new ArrayList<>();
for(int i=0; i<dataArray.length(); i++){
try {
JSONObject personJsonObject = dataArray.getJSONObject(i);
Person person = new Person();
if(personJsonObject.has("id") && !personJsonObject.isNull("id")){
person.setId(personJsonObject.getInt("id"));
}
if(personJsonObject.has("name") && !personJsonObject.isNull("name")){
person.setName(personJsonObject.getString("name"));
}
if(personJsonObject.has("email") && !personJsonObject.isNull("email")){
person.setEmail(personJsonObject.getString("email"));
}
if(personJsonObject.has("birthDate") && !personJsonObject.isNull("birthDate")){
person.setBirthDate(personJsonObject.getString("birthDate"));
}
personList.add(person);
}catch (JSONException e){
}
}
return personList;
}
4) Then use this list wherever you want.
Related
Actually I want to use tree Json response for my react native application. So I build that in spring boot. But due to "children": [] in last child I face some issue in react native. So I want to hide that from my response.
1.I got this type of response
[{
"id": 1,
"name": "Martin",
"haveAccount": false,
"gender": "m",
"children": [
{
"id": 4,
"name": "Werite",
"haveAccount": false,
"gender": "f",
"children": []
}
]
}]
2.But I don't want "children": [] in last child
example:-
[{
"id": 1,
"name": "Martin",
"haveAccount": false,
"gender": "m",
"children": [
{
"id": 4,
"name": "Werite",
"haveAccount": false,
"gender": "f"
}
]
}]
3.Here is my Entity class
#Service
#Entity
#Table
public class Family {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY )
#Column(name="Family_id")
private Integer id;
private String name;
private String village;
private String wifeName;
private String talukaName;
private Boolean haveAccount;
private String username;
private String gender;
private String mobileNumber;
#OneToOne
#JoinColumn(name = "parent_id")
#JsonBackReference
private Family parent;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
#JsonManagedReference
private List<Family> children = new ArrayList<>();
public Family(Integer id, String name, String village, String wifeName, String talukaName, Boolean haveAccount,
String username, String gender, String mobileNumber, Family parent, List<Family> children) {
super();
this.id = id;
this.name = name;
this.village = village;
this.wifeName = wifeName;
this.talukaName = talukaName;
this.haveAccount = haveAccount;
this.username = username;
this.gender = gender;
this.mobileNumber = mobileNumber;
this.parent = parent;
this.children = children;
}
public Family() {
super();
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Family getParent() {
return parent;
}
public void setParent(Family parent) {
this.parent = parent;
}
public List<Family> getChildren() {
return children;
}
public void setChildren(List<Family> children) {
this.children = children;
}
public void addChild(Family children) {
this.children.add(children);
}
public String getVillage() {
return village;
}
public void setVillage(String village) {
this.village = village;
}
public String getWifeName() {
return wifeName;
}
public void setWifeName(String wifeName) {
this.wifeName = wifeName;
}
public String getTalukaName() {
return talukaName;
}
public void setTalukaName(String talukaName) {
this.talukaName = talukaName;
}
public Boolean getHaveAccount() {
return haveAccount;
}
public void setHaveAccount(Boolean haveAccount) {
this.haveAccount = haveAccount;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMobileNumber() {
return mobileNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
If you want to delete a field you can put it a null and use #JsonInclude(Include.NON_NULL) on your class as follow:
#Service
#Entity
#Table
#JsonInclude(Include.NON_NULL)
public class Family {
//class
}
If you can handle that you should substitute private List<Family> children = new ArrayList<>(); with private List<Family> children; and initialize it when you are going to use it.
Just a question: Why are you using #Service on your entity class?
Below is my JSON data. I want to convert this to POJOs to store the Name,id,profession in a header table and the respective Jsonarray field in a child table.
JSON:
{
"Name": "Bob",
"id": 453345,
"Profession": "Clerk",
"Orders": [
{
"Item": "Milk",
"Qty": 3
},
{
"Item": "Bread",
"Qty": 3
}
]
}
Entity classes:
public class User {
private String name;
private Integer id;
private String Profession;
private JsonArray Orders;
private UserCart userCart;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProfession() {
return Profession;
}
public void setProfession(String profession) {
Profession = profession;
}
public JsonArray getOrders() {
return Orders;
}
public void setOrders(JsonArray orders) {
Orders = orders;
}
public UserCart getUserCart() {
return userCart;
}
public void setUserCart(UserCart userCart) {
this.userCart = userCart;
}
}
public class UserCart {
private String item;
private Integer qty;
public String getItem() {
return item;
}
public void setItem(String item) {
this.item = item;
}
public Integer getQty() {
return qty;
}
public void setQty(Integer qty) {
this.qty = qty;
}
}
But when I do below; I get error
Cannot deserialize instance of org.json.JSONArray out of START_ARRAY
token
User user = new User();
JsonNode data = new ObjectMapper().readTree(jsonString);
user = headerMap.readValue(data.toString(), User.class);
How do I go about assigning the entire JSON to both the Java objects ?
Use List<UserCart> for array data in json and use #JsonProperty for mapping different json node name to java object field. No need to use extra field (JsonArray Orders) anymore.
#JsonProperty("Orders")
private List<UserCart> userCart;
I have a json file like this:
{
"Student" : [
{
"name": "john",
"age": 12
}, {
"name": "jack",
"age": 20
}
]
}
and my Student class is:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
I want to make a Student Instance with name "jack" by using json
how can I do it?
Make Another Class Students which contain List<Student>.
public class Students {
List<Student> Student;
public List<Student> getStudents() {
return Student;
}
public void setStudent(List<Student> students) {
this.Student=students;
}
}
Gson gson = new Gson();
String jsonString = "Your Json String";
Students student = gson.fromJson(jsonString, Students.class);
I use org.json.simple library when I parse JSON
Excample:
excample App.java,
excample Information.java
List<Information> parseInformationObject(JSONArray infoList) {
List<Information> in = new ArrayList<>();
infoList.forEach(emp -> {
JSONObject info = (JSONObject) emp;
String id = info.get("id").toString();
String state = info.get("state").toString();
String type = null;
if (info.get("type") != null) {
type = info.get("type").toString();
}
String host = null;
if (info.get("host") != null) {
host = info.get("host").toString();
}
long timestamp = (long) info.get("timestamp");
in.add(new Information(id, state, type, host, timestamp));
});
return in;
}
I have a Spring application with 2 Entities that have a Many-to-Many relationship. There are Students and Groups. A student can be part of many groups and a group can have many students.
Student Model
#Entity
#Table(name = "STUDENTS")
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Student extends AbstractUser {
//Fields
#ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class)
#JoinTable(name = "GROUPS_STUDENTS",
joinColumns = { #JoinColumn(name = "student_id") },
inverseJoinColumns = { #JoinColumn(name = "group_id") })
private List<Group> groups = new ArrayList<Group>();
//Constructors
public Student(String password, String firstName, String lastName, String email){
super(password, firstName, lastName, email);
}
public Student(){
}
//Setters and getters
public List<Group> getGroups() {
return groups;
}
public void setGroups(List<Group> groups) {
this.groups = groups;
}
}
Group Model
#Entity
#Table(name = "GROUPS")
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id")
public class Group implements Item, Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name", nullable = false, unique = true)
private String name;
#Column(name = "year", nullable = false, length = 1)
private int year;
#ManyToMany(mappedBy = "groups", targetEntity = Student.class)
private List<Student> students;
public Group(String name, int yearOfStudy) {
this.setName(name);
this.setYear(yearOfStudy);
}
...
}
The problem is when I make a request to show all students, if 2 students are in the same group they appear in a hierarchy rather than one after another. What I mean the JSON is going too deep. I don't know how to explain exactly but I'll put an example.
How it appears
[
{
"id": 2,
"password": "$2a$10$bxieGA7kWuEYUUMbYNiYo.SbGpo7X5oh8ulUsqCcrIR2cFN2HiQP2",
"firstName": "First",
"lastName": "Last",
"email": "name#mail.com",
"groups": [
{
"id": 1,
"name": "G1",
"year": 0,
"users": [
2,
{
"id": 1,
"password": "$2a$10$9pfTdci7PeHtzxuAxjcOsOjPSswrU35/JOOeWPpgVhJI4tD2YpZdG",
"firstName": "John",
"lastName": "Smith",
"email": "john.smith#mail.com",
"groups": [
1
]
}
]
}
]
},
1
]
How it should appear
{
"id": 2,
"password": "$2a$10$bxieGA7kWuEYUUMbYNiYo.SbGpo7X5oh8ulUsqCcrIR2cFN2HiQP2",
"firstName": "First",
"lastName": "Last",
"email": "name#mail.com",
"groups": [
{
"id": 1,
"name": "G1",
"year": 0,
}
]
},
{
"id": 1,
"password": "$2a$10$9pfTdci7PeHtzxuAxjcOsOjPSswrU35/JOOeWPpgVhJI4tD2YpZdG",
"firstName": "John",
"lastName": "Smith",
"email": "john.smith#mail.com",
"groups": [
{
"id": 1,
"name": "G1",
"year": 0
}]
}
]
Do you have any idea how to solve this? I don't know exactly how to describe my problem and that's why I didn't find a solution yet. Any help will much appreciated. Thank you.
I've solved it. I've made a custom serializer. So in Group I'll serialize the students by setting a custom annotation #JsonSerialize(using = CustomStudentSerializer.class)
CustomStudentSerializer
public class CustomStudentSerializer extends StdSerializer<List<Student>> {
public CustomStudentSerializer() {
this(null);
}
public CustomStudentSerializer(Class<List<Student>> t) {
super(t);
}
#Override
public void serialize(
List<Student> students,
JsonGenerator generator,
SerializerProvider provider)
throws IOException, JsonProcessingException {
List<Student> studs = new ArrayList<>();
for (Student s : students) {
s.setGroups(null);
studs.add(s);
}
generator.writeObject(studs);
}
}
Did the same for the groups. I've just removed the students/group component when the relationship is already nested. And now it works just fine.
Took me a while to figure this out but I posted here because it may help someone else too.
Using the #JsonIgnoreProperties annotation is another alternative:
#Entity
public class Student extends AbstractUser {
#ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class)
#JoinTable(name = "GROUPS_STUDENTS",
joinColumns = { #JoinColumn(name = "student_id") },
inverseJoinColumns = { #JoinColumn(name = "group_id") })
#JsonIgnoreProperties("students")
private List<Group> groups = new ArrayList<Group>();
}
#Entity
public class Group implements Item, Serializable {
#ManyToMany(mappedBy = "groups", targetEntity = Student.class)
#JsonIgnoreProperties("groups")
private List<Student> students;
}
Find comparison between #JsonManagedReference+#JsonBackReference, #JsonIdentityInfo and #JsonIgnoreProperties here: http://springquay.blogspot.com/2016/01/new-approach-to-solve-json-recursive.html
To solve jackson infinite recursion you can use #JsonManagedReference, #JsonBackReference.
#JsonManagedReference is the forward part of reference – the one that
gets serialized normally.
#JsonBackReference is the back part of
reference – it will be omitted from serialization.
Find more details here: http://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion
public class Student extends AbstractUser {
#ManyToMany(fetch = FetchType.LAZY, targetEntity = Group.class)
#JoinTable(name = "GROUPS_STUDENTS",
joinColumns = { #JoinColumn(name = "student_id") },
inverseJoinColumns = { #JoinColumn(name = "group_id") })
#JsonManagedReference
private List<Group> groups = new ArrayList<Group>();
}
public class Group implements Item, Serializable {
#ManyToMany(mappedBy = "groups", targetEntity = Student.class)
#JsonBackReference
private List<Student> students;
}
Or you can use DTO (Data Transfer Object) classes. These are plain code classes wich you can set to your needs when sendind data. For example, for your case you can have:
UserDTO.java:
import java.util.List;
public class UserDTO {
private int id;
private String password;
private String firstName;
private String lastName;
private String email;
private List<GroupDTO> groups;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
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 String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public List<GroupDTO> getGroups() {
return groups;
}
public void setGroups(List<GroupDTO> groups) {
this.groups = groups;
}
}
GroupDTO.java
package temp;
public class GroupDTO {
private int id;
private String name;
private int year;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
}
This way you can customize the information you will send in the json file.
Let's say you have a User class and you want to send all users information:
List<StudentDTO> response = new ArrayList<StudentDTO>(); //List to be send
List<Student> students = bussinessDelegate.findAllStudents(); //Or whatever you do to get all students
for (int i = 0; i < students.size(); i++) {
Student student = students.get(i);
StudentDTO studentDTO = new StudentDTO(); //Empty constructor
studentDTO.setEmail(student.getEmail());
studentDTO.setFirstName(student.getFirstName());
studentDTO.setLastName(student.getLastName());
studentDTO.setId(student.getId());
studentDTO.setPassword(student.getPassword());
List<Group> studentGroups = student.getGroups();
List<GroupDTO> studentGroupsDTO = new ArrayList<GroupDTO>();
for (int j = 0; j < studentGroups.size(); j++) {
Group group = studentGroups.get(j);
GroupDTO groupDTO = new GroupDTO();
groupDTO.setId(group.getId());
groupDTO.setName(group.getName());
groupDTO.setYear(group.getYear());
studentGroupsDTO.add(groupDTO);
}
studentDTO.setGroups(studentGroupsDTO);
response.add(studentDTO);
}
//Here you have your response list of students ready to send`
If you want to be able to dynamically define what has to be serialized you could try my jackson addon which i developed based on the question here:
https://stackoverflow.com/a/28245875/869225
This also helped me with backreferences.
I'm trying to access variables from an inner class of a deserialized json object. Below is the code I've used.
package jsonparser;
public class JsonParser {
private long uid = 0;
private String username, secret, filter, machine_id, access_token,
session_key = null;
public JsonParser() {
}
public static class Profile {
private String last_name, first_name, pic_square, name = null;
private long uid = 0;
final JsonParser outer = JsonParser.this;
public String getLast_name() {
return last_name;
}
public void setLast_name(String last_name) {
this.last_name = last_name;
}
public String getFirst_name() {
return first_name;
}
public void setFirst_name(String first_name) {
this.first_name = first_name;
}
public String getPic_square() {
return pic_square;
}
public void setPic_square(String pic_square) {
this.pic_square = pic_square;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getUid() {
return uid;
}
public void setUid(long uid) {
this.uid = uid;
}
public Profile() {
}
}
}
And in another class:
JsonParser jp = gson.fromJson(Data, JsonParser.class);
where Data looks like:
{
"uid": 123,
"username": "Hello",
"secret": "87920",
"filter": "nf",
"machine_id": "machine_id",
"access_token": "access_token",
"session_key": "123e",
"profile": {
"last_name": "Tan",
"uid": 123,
"first_name": "Sally",
"pic_square": "url.jpg",
"name": "Sally Tan"
}
}
How would I be able to access the last_name in the profile inner class from the jp object?
Add a field
private Profile profile;
public Profile getProfile() { return profile; }
to the outer class JsonParser. Then you can use
jp.getProfile().getLast_name();
Note: The name JsonParser is confusing since it doesn't parse anything - it stores the parse results. Rename it to Config or something like that.
First remove
final JsonParser outer = JsonParser.this;
from your code. This is an illegal construct because this cannot be referenced from a static context.
Then add
private Profile profile;
to your JsonParser class right below the definition of the other members like username, secret,...
With this member in place the GSon Parser will fill it on your call to gson.fromJson(...).
You can add a getter Method to access your sub-structure from outside.