group by a field in Java Streams - java

So, I have an input JSON that looks like this:
[{
"added": "2014-02-01T09:13:00Z",
"author": {
"id": "1",
"name": "George R R Martin",
"added_on": "2013-02-01T09:13:00Z"
},
"book": {
"id": "12",
"name": "Game of Thrones",
"genre": "Fantasy Fiction"
}
},
{
"added": "2015-02-01T09:13:00Z",
"author": {
"id": "2",
"name": "Patrick Rothfuss",
"added_on": "2012-09-13T011:40:00Z"
},
"book": {
"id": "15",
"name": "The Name of the Wind",
"genre": "Fantasy Fiction"
}
}, {
"added": "2016-02-01T09:13:00Z",
"author": {
"id": "2",
"name": "Patrick Rothfuss",
"added_on": "2012-09-13T011:40:00Z"
},
"book": {
"id": "17",
"name": "The Wise Man's Fear",
"genre": "Fantasy Fiction"
}
}]
I need to group it basis on author.id. An author will have one object and a list of all the books he's authored.
This is what I expect the output:
[
{
"author": "George R R Martin",
"added_on": "2013-02-01T09:13:00Z",
"books": [
{
"book_name": "Game of Thrones",
"added": "2014-02-01T09:13:00Z"
}
]
},
{
"author": "Patrick Rothfuss",
"added_on": "2012-09-13T011:40:00Z",
"books": [
{
"book_name": "The Name of the Wind",
"added": "2015-02-01T09:13:00Z"
}, {
"book_name": "The Wise Man's Fear",
"added": "2016-02-01T09:13:00Z"
}
]
}
]
I tried doing it through a normal for loop -- it works. But, just for the sake of learning more about Streams, I want to try it out using Streams.
I tried this:
Map<Author, List<Book>> collect = authorsList.stream()
.collect(Collectors.groupingBy(AuthorBookObj::getAuthor,
Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));
But, didn't get what I needed. Instead, it created three Maps instead of two.
Also tried this:
Map<AuthorTuple, List<Book>> collect = authorsList.stream()
.collect(Collectors.groupingBy(authors -> new AuthorTuple(authors.getAuthor().getId(),
authors.getAuthor().getName(), authors.getAuthor().getAddedOn()),
Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));
It also gives me three objects in the list. I expected to have two authors and corresponding books for each author.
AuthBookObj:
public class AuthorBookObj
{
private String id;
private Author author;
private Book book;
private String added;
//getter, setter
}
public class Article
{
private String name;
private String id;
private String genre;
}
public class Author
{
private String name;
private String added_on;
private String id;
}

The problem is not the way you handle the stream, it is in the equality of the objects.
The correct way is to use this code:
Map<Author, List<Book>> collect = authorsList.stream()
.collect(Collectors.groupingBy(AuthorBookObj::getAuthor,
Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));
But now you are comparing Author objects, since the objects are different you get three entries. You need to add a hashcode and equals in the Author object that will compare the objects on the author id.
//code generated from intellij.
// Author.java
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Author author = (Author) o;
return getId() == author.getId();
}
#Override
public int hashCode() {
return Objects.hash(getId());
}

If you don't have limitation on creating new POJO classes on requirement, i will do in this way
First to parse the input JSON to java object
Response class with AuthorDetails and BookDetails class
class Response {
private String addedOn;
private AuthorDetails author;
private BookDetails book;
}
AuthorDetails
class AuthorDetails {
private String id;
private String name;
private String addedOn;
}
BookDetails
class BookDetails {
private String id;
private String name;
private String gener;
}
And i will map the input json to List<Response>
List<Response> list = Arrays.asList(new Response());
Then now converting List<Response> into desired output i have added couple of POJO classes
AuthorAndBooks
class AuthorAndBooks {
#JsonProperty("author")
private String author;
#JsonProperty("added_on")
private String addedOn;
#JsonProperty("books")
List<AuthorBooks> books;
}
AuthorBooks
class AuthorBooks {
#JsonProperty("book_name")
private String name;
#JsonProperty("added")
private String added;
}
Now do group by based on author name
Map<String, List<Response>> group = list.stream().
collect(Collectors.groupingBy(res->res.getAuthor().getName()));
And now for every Author add the books
List<AuthorAndBooks> authorBooks = group.entrySet().stream().
map(entry->{
AuthorAndBooks ab = new AuthorAndBooks();
ab.setAuthor(entry.getKey());
ab.setAddedOn(entry.getValue().stream().findFirst().get().getAddedOn());
ab.setBooks(entry.getValue().stream().map(authorBook->{
AuthorBooks books = new AuthorBooks();
books.setName(authorBook.getBook().getName());
books.setAdded(authorBook.getAddedOn());
return books;
}).collect(Collectors.toList()));
return ab;
}).collect(Collectors.toList());

First of all want to pay attention to "added" field from input JSON. What does this belong to? I guess it belongs to Book object. If so it would be good to place this field (if it possible) inside Book object. Then you need to deserialize this json to java objects. It can be done by com.fasterxml.jackson.databind.ObjectMapper But you can use any json framework for this.
ObjectMapper mapper = new ObjectMapper();
AuthorBookObj[] objs = mapper.readValue(inputJson, AuthorBookObj[].class);
Then you need to group these objects and your first solution is well suited:
Map<Author, List<Book>> collect = Arrays.stream(objs)
.collect(groupingBy(AuthorBookObj::getAuthor,
mapping(AuthorBookObj::getBook, toList())));
How it was mentioned in previous answer you need to make sure there are equals/hashcode methods in your class that is used for as key in Map (In this case Author). The main confuse now is that desirable json output doesn't represent Map. It is just list of some custom object with fields like author, added_on, books which is list also.
So to achieve this goal you need to transform your Map<Author, List<Book>> to list of custom objects. For example:
public class PublicationInfo {
private String author;
private String added_on;
private List<BookBriefInfo> books;
...
}
public class BookBriefInfo {
private String book_name;
private String added;
...
}
List<PublicationInfo> infos = new ArrayList<>();
for (Map.Entry<Author, List<Book>> entry : collect.entrySet()) {
PublicationInfo info = new PublicationInfo();
info.setAuthor(entry.getKey().getName());
info.setAdded_on(entry.getKey().getAdded_on());
List<BookBriefInfo> bookInfos = new ArrayList<>();
for (Book book : entry.getValue()) {
bookInfos.add(new BookBriefInfo(book.getBook_name(), book.getAdded()))
}
info.setBooks(bookInfos);
}
Finally it can be serialized:
String jsonResult = mapper.writeValueAsString(infos);
By the way, to get json output formatted just configure it:
mapper.configure(SerializationFeature.INDENT_OUTPUT, true);

You must override equals and hashCode. If you fail to do so, your class will violate the general contract for hashCode, which will prevent it from functioning properly in collections such as HashMap and HashSet. The Author class’s failure to override hashCode causes the two equal instances to have unequal hash codes, in violation of the hashCode contract. Add this to your Author class.
#Override
public int hashCode() {
return id.hashCode();
}
#Override
public boolean equals(Object obj) {
return obj instanceof Author && ((Author) obj).getId().equals(id);
}
With that in place, the following code snippet should work as expected.
Map<Author, List<Article>> booksByAuthor = authorsList.stream()
.collect(Collectors
.groupingBy(AuthorBookObj::getAuthor,
Collectors.mapping(AuthorBookObj::getBook, Collectors.toList())));

Related

Populate List inside List With Conditionals Java

I'm trying to populate a List<Object> that has as a attribute another List.
Here is The Scenario.
First Object
public class Student {
private String initials;
private String id;
private List<StudentDetail> listStudentDetail;
//Setters and Getters
}
Second Object
public class StudentDetail {
private String id;
private String name;
//Setters and getters
}
My final java object is as follows.
public class Response {
private String code;
private String message;
private List<Student> listStudent;
//Setters and getters
}
I get populated a List<Student>and a List<StudentDetail> from another process and what I want to achive is merge both list into my Response class but with theese particular conditions
In order to fill List<StudentDetail>
Student.initials must be "a"
Student.id = StudentDetail.id
These is what I want to Achieve.
{
"code": "0",
"message": "Succes",
"listStudent": [
{
"initials": "a",
"id": "104",
"listStudentDetail": [
{
"id": "104",
"name": "Kevin"
}
]
},
{
"initials": "b",
"id": "100",
"listStudentDetail": []
},
{
"initials": "a",
"id": "105",
"listStudentDetail": [
{
"id": "105",
"name": "Robert"
}
]
}
]
}
Here is the code.
I am assuming populatedStudentList and populatedStudentDetail as the given objects that have been populated in some other part of the code like you mentioned.
for (Student s in populatedStudentList){
if (s.getInitials().compareTo('a') != 0){
continue;
}
String findId = s.getId();
List<StudentDetail> tempListStudentDetail = new ArrayList<>();
for (StudentDetail d in populatedStudentDetail){
if (d.getId().compareTo(findId) == 0){
tempListStudentDetail.append(d);
}
}
s.setListStudentDetail(tempListStudentDetail);
}
This can be achieved in a more memory efficient manner using hashTables but I have tried to reproduce the desired result in the most basic manner.

How to create one generic jsondatareader class for different JSON

I have created customer json file as below:
[
{
"firstName": “test”,
"lastName": “temp”,
"age": 35,
"emailAddress": “test#Gmail.com",
"address": {
"streetAddress": “test testing“,
"city": “city”,
"postCode": “12343546”,
"state": “state”,
"country": “cy”,
"county": “abc”
},
"phoneNumber": {
"home": "012345678",
"mob": "0987654321"
}
},
{
"firstName": “tug”,
"lastName": “kjk”,
"age": 35,
"emailAddress": “jhgj#Gmail.com",
"address": {
"streetAddress": “jh hjgjhg ,
"city": “kjhjh”,
"postCode": "122345",
"state": “jhgl”,
"country": “jaj”,
"county": “jhgkg”
},
"phoneNumber": {
"home": "012345678",
"mob": "0987654321"
}
}
]
For the Customer JSON data file, I have created below JSON datareader class:
public class JsonDataReader {
private final String customerFilePath = new ConfigFileReader().getTestDataResourcePath() + "Customer.json";
private List<Customer> customerList;
public JsonDataReader(){
customerList = getCustomerData();
}
private List<Customer> getCustomerData() {
Gson gson = new Gson();
BufferedReader bufferReader = null;
try {
bufferReader = new BufferedReader(new FileReader(customerFilePath));
Customer[] customers = gson.fromJson(bufferReader, Customer[].class);
return Arrays.asList(customers);
}catch(FileNotFoundException e) {
throw new RuntimeException("Json file not found at path : " + customerFilePath);
}finally {
try { if(bufferReader != null) bufferReader.close();}
catch (IOException ignore) {}
}
}
public final Customer getCustomerByName(String customerName){
for(Customer customer : customerList) {
if(customer.firstName.equalsIgnoreCase(customerName)) return customer;
}
return null;
}
}
Created POJO class as below:
public class Customer {
public String firstName;
public String lastName;
public int age;
public String emailAddress;
public Address address;
public PhoneNumber phoneNumber;
public class Address {
public String streetAddress;
public String city;
public String postCode;
public String state;
public String country;
public String county;
}
public class PhoneNumber {
public String home;
public String mob;
}
}
This is working fine so far as there is only one JSON data file, however I will create more JSON data files, so may be I have to create multiple POJOs for each one, but is there any way I can write common generic jsondatareader class for all those JSON files?
A class (or an Object) is a well defined entity. By well defined I mean that its structure is known at compile time, and cannot be changed after that point.
Having to create multiple classes to represent multiple JSON documents is perfectly fine. So if you're worried about the amount of files you'll create, it's a non-problem.
But, if the JSON document structure will keep changing along with every request, there is no point in defining a series of classes. To handle totally dynamic JSON you should stick with what Gson offers you. That is JsonElement and its subclasses.
JsonElement
> JsonArray
> JsonObject
> JsonPrimitive
> JsonNull
That's all what is needed to describe a JSON object.
If that is the case then why not convert JSON into a Map instead of a POJO! If you go POJO route then you will utilizing Jackson or GSon heavily in your code base adding bunch of utility methods to iterate over every resulting JSonArray or JSonelements.

Deserialize JSON entities to POJO with ID references

Lets say we have the following JSON example:
{
"teachers": [{
"id": "abc",
"payment": 10,
"name": "xyz",
"clases": ["1", "3"]
}, {
"id": "qwe",
"payment": 12,
"name": "xcv",
"classes": ["1", "2"]
}],
"classes": [{
"id": "1",
"room": 7
}, {
"id": "2",
"room": 1
}, {
"id": "3",
"room": 2
}]
}
I would like to deserialize it to Java objects (getters/setters ommited):
class Teacher {
private String id;
private double payment;
private String name;
private List<CLassRoom> classRooms;
}
class ClassRoom {
private String id;
private int room;
}
As you see, we have a references here. I know I can deserialize it with Jackson (and would like to) but the problem is that I cannot touch DTO itself (so annotations are not possible, would also like to avoid wrappers (many classes)). Also, it would be nice if the "configuration" of deserialization was in separate file (json schema for example). I would also like to avoid some tags given by user - he should only pass me the values. Moreover, he should know where is the error, if he made some mistake.
Also, it would be nice if I could manipulate name of field in json (some clients may have different habits).
I didn't find anything which satisffied all of above requirements(entity reference and error handling are the most important). However - I just have heard about json schema, so maybe it provides such functionality (but I didn't find it though). Any helpful reference/example/lib? I will appreciate any help.
Just to be correct - imagine that the given json is a RELATIONAL database snapshot of the instance. I just want to create whole entity like the hibernate (or actually JPA) does :)
1. add jar of import org.json.JSONObject.
2. JSONObject object = new JSONObject(list)
2.1 object.has("teachers") if it is exists
2.2 JSONArray teacherArray = (JSONArray) object.get("teachers");
2.3 JSONObject teacherJsonObject = teacherArray .getJSONObject(0);
(if you have more than jsonobject in json arrary then itrate it.)
2.4 if(teacherJsonObject .has("id"))//you can check existence like this.
String id=teacherJsonObject .getString("id");
String payment=teacherJsonObject .getString("payment");
String name=teacherJsonObject .getString("name");
It may not be the best solution, but it's a working one.
Let's create a Parser class like the following:
public class Parser {
private List<Teacher> teachers;
private List<ClassRoom> classes;
public void parse() {
for (Teacher teacher : teachers) {
for (String classRoomId : teacher.getClasses()) {
for (ClassRoom classRoom : classes) {
if (classRoom.getId().equals(classRoomId)) {
teacher.getClassRooms().add(classRoom);
}
}
}
}
}
}
Modify your ClassRoom class to have a getter on the id field:
public class ClassRoom {
private String id;
private int room;
public String getId() {
return id;
}
}
And your Teacher class to get the Ids of classes AND the classRooms references:
public class Teacher {
private String id;
private double payment;
private String name;
private String[] classes;
private List<ClassRoom> classRooms = new ArrayList<>();
public String[] getClasses() {
return classes;
}
public List<ClassRoom> getClassRooms() {
return classRooms;
}
}
If you use the Gson library, you could then just parse your JSON like that:
Gson gson = new Gson();
Parser parser = gson.fromJson(jsonString, Parser.class);
parser.parse;
Now, every teacher will have their classRooms correctly referenced.

JSON Array of objects to plain old java object

this is my first time making an external api call in Java, so please bear with me as I'm not very experienced. I got the http request working and got a response, but now I need to parse it.
I'm trying to convert a json array to java objects. I understand the gist of it, but all examples I've seen don't apply to my issue.
I need the 'entities' objects from the json string. The details (which are an array, too) can contain any key/value pair, so I was thinking of putting that in a hashmap in each Entity object. I've tried the gson library, but I can't find any gson example that goes deeper than a single dimensional json array.
I realize this is kind of a broad question, and I don't expect anyone to deliver me a working solution, but a few tips or a link to a relevant guide would go a long way. :)
{
"return": {
"entities": [
{
"id": 2385,
"details": [
{
"name": "Other Known Name",
"value": "John Wick",
"match": false
}
],
"proofs": [],
"link": "http://domain.gg/users?id=2385"
},
{
"id": 2384,
"details": [
{
"name": "Discord ID",
"value": "159985870458322944",
"match": false
},
{
"name": "SteamID64",
"value": "76561197991558078",
"match": true
},
{
"name": "SteamVanity",
"value": "test",
"match": false
},
{
"name": "PS4",
"value": "John_S",
"match": false
},
{
"name": "XBox",
"value": "John S",
"match": false
},
{
"name": "Email",
"value": "john_smith#gmail.com",
"match": true
},
{
"name": "Comment",
"value": "Test user",
"match": false
},
{
"name": "Other Known Name",
"value": "Jonathan",
"match": false
},
{
"name": "Reddit",
"value": "/u/johns",
"match": true
}
],
"proofs": [],
"link": "http://domain.gg/users?id=2384"
},
{
"id": 1680,
"details": [
{
"name": "Other Known Name",
"value": "Johny",
"match": false
},
{
"name": "SteamID64",
"value": "76561198213003675",
"match": true
}
],
"proofs": [],
"link": "http://domain.gg/users?id=1680"
},
{
"id": 1689,
"details": [
{
"name": "Other Known Name",
"value": "JohnnyPeto",
"match": false
},
{
"name": "SteamID64",
"value": "76561198094228192",
"match": true
}
],
"proofs": [],
"link": "http://domain.gg/users?id=1689"
}
],
"notice": "Showing 4 out of 4 matches."
}
}
There are many json serialization/deserialization frameworks available. I would recommend having a look at Jackson.
Basically, you have to create Model corresponding to json schema and deserialize json into object. Based on the example in the question, model will look like this:
#JsonIgnoreProperties(ignoreUnknown = true)
class Response {
#JsonProperty("return")
private ResponseObject responseObject;
public ResponseObject getResponseObject() {
return responseObject;
}
public void setResponseObject(ResponseObject responseObject) {
this.responseObject = responseObject;
}
}
#JsonIgnoreProperties(ignoreUnknown = true)
class ResponseObject {
private List<Entity> entities;
public List<Entity> getEntities() {
return entities;
}
public void setEntities(List<Entity> entities) {
this.entities = entities;
}
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Entity {
private String id;
private List<Details> details;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<Details> getDetails() {
return details;
}
public void setDetails(List<Details> details) {
this.details = details;
}
}
#JsonIgnoreProperties(ignoreUnknown = true)
class Details {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Once the model is defined, you can use ObjectMapper class to perform serialization/deserialization, e.g.:
ObjectMapper mapper = new ObjectMapper();
Response response = mapper.readValue("{\"return\": {\"entities\": [{\"id\": 2385,\"details\": [{\"name\": \"Other Known Name\",\"value\": \"John Wick\",\"match\": false}],\"proofs\": [],\"link\": \"http://domain.gg/users?id=2385\"},{\"id\": 2384,\"details\": [{\"name\": \"Discord ID\",\"value\": \"159985870458322944\",\"match\": false},{\"name\": \"SteamID64\",\"value\": \"76561197991558078\",\"match\": true},{\"name\": \"SteamVanity\",\"value\": \"test\",\"match\": false},{\"name\": \"PS4\",\"value\": \"John_S\",\"match\": false},{\"name\": \"XBox\",\"value\": \"John S\",\"match\": false},{\"name\": \"Email\",\"value\": \"john_smith#gmail.com\",\"match\": true},{\"name\": \"Comment\",\"value\": \"Test user\",\"match\": false},{\"name\": \"Other Known Name\",\"value\": \"Jonathan\",\"match\": false},{\"name\": \"Reddit\",\"value\": \"/u/johns\",\"match\": true}],\"proofs\": [],\"link\": \"http://domain.gg/users?id=2384\"},{\"id\": 1680,\"details\": [{\"name\": \"Other Known Name\",\"value\": \"Johny\",\"match\": false},{\"name\": \"SteamID64\",\"value\": \"76561198213003675\",\"match\": true}],\"proofs\": [],\"link\": \"http://domain.gg/users?id=1680\"},{\"id\": 1689,\"details\": [{\"name\": \"Other Known Name\",\"value\": \"JohnnyPeto\",\"match\": false},{\"name\": \"SteamID64\",\"value\": \"76561198094228192\",\"match\": true}],\"proofs\": [],\"link\": \"http://domain.gg/users?id=1689\"}],\"notice\": \"Showing 4 out of 4 matches.\"}}", Response.class);
System.out.println(response.getResponseObject().getEntities().get(0).getId());
Here's the Javadoc.
If I were you, I'd use Jackson, not GSON. It's specialized on JavaBeans-style mapping. Write classes like this:
public class Detail{
private String name;
private String value;
private boolean match;
// + getters / setters
}
public class Entity{
private int id;
private List<Detail> details;
private String link;
private List<String> proofs;
// you don't have any example data for this, so I'm assuming strings
// + getters / setters
}
public class Result{
private List<Entity> entities;
private String notice;
// + getters / setters
}
and do the conversion with something like
Result result = new ObjectMapper().readValue(json, Result.class);
As my fellow stackoverflow users have previously posted, for this kind of initilization Jackson API would be better. I have however posted the solution for your question with Gson.
I noticed that you like your details to be stored as a HashMap with id as key. However, it seems like this id is actually related to the entities and not to the details.
Disclaimer, I got lazy and used an online POJO generator because I did not want to create objects for all of the Json elements ;) It still showcases how it should be done:
class Main{
public static void main(String[] args) throws FileNotFoundException {
//this is just to load the json file
String input = new Scanner(new File("test.txt")).useDelimiter("\\Z").next();
System.out.println(input);
Gson gson = new Gson();
Example arr = gson.fromJson(input, Example.class);
System.out.println(arr);
}
public class Detail {
#SerializedName("name")
#Expose
public String name;
#SerializedName("value")
#Expose
public String value;
#SerializedName("match")
#Expose
public Boolean match;
#Override
public String toString() {
return "Detail [name=" + name + ", value=" + value + ", match=" + match + "]";
}
}
public class Entity {
#SerializedName("id")
#Expose
public Integer id;
#SerializedName("details")
#Expose
public List<Detail> details = null;
#SerializedName("proofs")
#Expose
public List<Object> proofs = null;
#SerializedName("link")
#Expose
public String link;
#Override
public String toString() {
return "Entity [id=" + id + ", details=" + details + ", proofs=" + proofs + ", link=" + link + "]";
}
}
public class Example {
#SerializedName("return")
#Expose
public Return _return;
#Override
public String toString() {
return "Example [_return=" + _return + "]";
}
}
public class Return {
#SerializedName("entities")
#Expose
public List<Entity> entities = null;
#SerializedName("notice")
#Expose
public String notice;
#Override
public String toString() {
return "Return [entities=" + entities + ", notice=" + notice + "]";
}
}
}
Output
Example [_return=Return [entities=[Entity [id=2385, details=[Detail [name=Other Known Name, value=John Wick, match=false]], proofs=[], link=http://domain.gg/users?id=2385], Entity [id=2384, details=[Detail [name=Discord ID, value=159985870458322944, match=false], Detail [name=SteamID64, value=76561197991558078, match=true], Detail [name=SteamVanity, value=test, match=false], Detail [name=PS4, value=John_S, match=false], Detail [name=XBox, value=John S, match=false], Detail [name=Email, value=john_smith#gmail.com, match=true], Detail [name=Comment, value=Test user, match=false], Detail [name=Other Known Name, value=Jonathan, match=false], Detail [name=Reddit, value=/u/johns, match=true]], proofs=[], link=http://domain.gg/users?id=2384], Entity [id=1680, details=[Detail [name=Other Known Name, value=Johny, match=false], Detail [name=SteamID64, value=76561198213003675, match=true]], proofs=[], link=http://domain.gg/users?id=1680], Entity [id=1689, details=[Detail [name=Other Known Name, value=JohnnyPeto, match=false], Detail [name=SteamID64, value=76561198094228192, match=true]], proofs=[], link=http://domain.gg/users?id=1689]], notice=Showing 4 out of 4 matches.]]
Despite there are answers suggesting you to use Jackson, you can still accomplish easily with Gson with its default configuration just creating proper relations between mappings:
// A generic response, parameterized with <T>, can hold any type except of primitives
final class Response<T> {
#SerializedName("return")
final T ret = null;
}
final class EntitiesAndNotice {
final List<Entity> entities = null;
final String notice = null;
}
final class Entity {
// Unlike Object and any its subclasses, `int` being a primitive cannot be nulled
// Simple 0 won't work either, because the compiler will inline it
// So it's a sort of cheating javac to return a value that holds 0 already
final int id = Integer.valueOf(0);
final List<Detail> details = null;
// Your JSON document does not provide enough info on the elements type
// So it depends on how Gson parses JSON tokens
final List<Object> proofs = null;
final URL link = null;
}
final class Detail {
final String name = null;
final String value = null;
// The same for primitive booleans, or Boolean.FALSE
final boolean match = Boolean.valueOf(false);
}
Example use:
private static final String JSON = "{\"return\":{\"entities\":[{\"id\":2385,\"details\":[{\"name\":\"Other Known Name\",\"value\":\"John Wick\",\"match\":false}],\"proofs\":[],\"link\":\"http://domain.gg/users?id=2385\"},{\"id\":2384,\"details\":[{\"name\":\"Discord ID\",\"value\":\"159985870458322944\",\"match\":false},{\"name\":\"SteamID64\",\"value\":\"76561197991558078\",\"match\":true},{\"name\":\"SteamVanity\",\"value\":\"test\",\"match\":false},{\"name\":\"PS4\",\"value\":\"John_S\",\"match\":false},{\"name\":\"XBox\",\"value\":\"John S\",\"match\":false},{\"name\":\"Email\",\"value\":\"john_smith#gmail.com\",\"match\":true},{\"name\":\"Comment\",\"value\":\"Test user\",\"match\":false},{\"name\":\"Other Known Name\",\"value\":\"Jonathan\",\"match\":false},{\"name\":\"Reddit\",\"value\":\"/u/johns\",\"match\":true}],\"proofs\":[],\"link\":\"http://domain.gg/users?id=2384\"},{\"id\":1680,\"details\":[{\"name\":\"Other Known Name\",\"value\":\"Johny\",\"match\":false},{\"name\":\"SteamID64\",\"value\":\"76561198213003675\",\"match\":true}],\"proofs\":[],\"link\":\"http://domain.gg/users?id=1680\"},{\"id\":1689,\"details\":[{\"name\":\"Other Known Name\",\"value\":\"JohnnyPeto\",\"match\":false},{\"name\":\"SteamID64\",\"value\":\"76561198094228192\",\"match\":true}],\"proofs\":[],\"link\":\"http://domain.gg/users?id=1689\"}],\"notice\":\"Showing 4 out of 4 matches.\"}}";
private static final Gson gson = new Gson();
private static final TypeToken<Response<EntitiesAndNotice>> responseTypeToken = new TypeToken<Response<EntitiesAndNotice>>() {
};
public static void main(final String... args) {
final Response<EntitiesAndNotice> response = gson.fromJson(JSON, responseTypeToken.getType());
final String value = response.ret.entities.get(1).details.get(3).value;
System.out.println(value);
}
Output:
John_S

Insert and Get operations on JSON object in MongoDB with Spring Boot

How can I save JSON object with different level of hierarchies in MongoDB ?
For example :-JSON
{
"name": "abc",
"password": "xyz",
"address": {
"street": "ghgjk",
"pin": 25646
},
"readingHabbits": [
"jkjsdj",
"sdkhks",
"jlcsd"
],
"eatingHabbits": {
"internalObjOne": {
"dkks": "jdskdfl",
"lfld": "hfslvlsk"
},
"internalObjectSecond": {
"cjdlksl": "hcdkjnjkcs",
"cjsdjljsl": "chsdskjc"
}
}
}
How can I store above JSON values into MongoDB in different Collections using SpringBoot and Java?
Also how can I get the same result when I do repository.findAll();
It should look like this:
db.getCollection("images").insertOne(
new Document("name", "abc")
.append("password", "xyz")
.append("address",
new Document()
.append("street", "ghgjk")
.append("pin", 25646))
.append("readingHabbits", Arrays.asList("jkjsdj", "sdkhks", "jlcsd"))
.append("eatingHabbits", Arrays.asList(
new Document()
.append("internalObjOne",
new Document()
.append("dkks", "jdskdfl")
.append("lfld", "hfslvlsk")),
new Document()
.append("internalObjectSecond",
new Document()
.append("cjdlksl", "hcdkjnjkcs")
.append("cjsdjljsl", "chsdskjc"))
)
)
);
thanks for the answer, But I think I didn't made myself clear.
Suppose I have a json object.
{ "name": "abc", "password": "xyz", "address": { "street": "ghgjk", "pin": 25646 }, "readingHabbits": [ "jkjsdj", "sdkhks", "jlcsd" ], "eatingHabbits": { "internalObjOne": { "dkks": "jdskdfl", "lfld": "hfslvlsk" }, "internalObjectSecond": { "cjdlksl": "hcdkjnjkcs", "cjsdjljsl": "chsdskjc" } } }
Base class :-
#Document(collection="user")
public class User{
#Id
private String id;
private String name;
private String password;
#DBRef
private Address address;
#DBRef
private ReadingHabbits readingHabbits;
//setter and getter
}
#Document(collection="address")
public class Address{
#Id
private String id;
private String street;
private int pin;
//setter and getter
}
Do we need to create separate classes for "ReadingHabbits" and "EatingHabbits" ?
If not then is the above approach correct to map two different entities with DBRef and save it to two different collection in MongoDB?
Or do we have any other way to do the same operation ?
----------

Categories