Map Flux into business DTO with list - java

I have the following entity:
public class EventCategoryEntity {
private UUID id;
#Column("category_name")
private String categoryName;
#Column("group_name")
private String groupName;
}
Which I retrieve via Flux(one to many relationship):
public Flux<EventCategoryEntity> findAllCategories() {
return eventRepository.findAll();
}
#Query("select ec.id, ec.name as category_name,ecg.name as group_name" +
"from event_category ec left join event_category_relation ecr on (ec.id = ecr.event_category_id) " +
"left join event_category_group ecg on (ecr.event_category_group_id = ecg.id);")
Flux<EventCategoryEntity> findAll();
Then output via Controller in JSON response like:
{
"id": "87108493-4fc1-4b12-8ffc-e10aa039fc39",
"categoryName": "soccer",
"groupName": "team",
},
{
"id": "87108493-4fc1-4b12-8ffc-e10aa039fc39",
"categoryName": "soccer",
"groupName": "ball",
}
]
But I would like to aggregate response by id like this:
[
{
"id": "87108493-4fc1-4b12-8ffc-e10aa039fc39",
"categoryName": "soccer",
"groupName: ["team", "ball"]
}
]
I've prepared DTO object, but I don't know how this flux map into the this:
public class EventCategory {
private UUID id;
private String categoryName;
private List<CategoryGroup> categoryGroup;
private class CategoryGroup {
private String groupName;
}
}

You can use collectMultimap which collects all elements emitted by this Flux into a Map.
#Test
public void collectMultimap() {
Flux<EventCategoryEntity> flux1 = Flux.just(
new EventCategoryEntity("87108493-4fc1-4b12-8ffc-e10aa039fc39","soccer","team"),
new EventCategoryEntity("87108493-4fc1-4b12-8ffc-e10aa039fc39","soccer","ball"),
new EventCategoryEntity("57108499-4fc1-4b52-8ffc-e11aa039fc85","soccer","tennis")
);
flux1.collectMultimap(EventCategoryEntity::getId, EventCategoryEntity::getGroupName)
.map(ids -> ids.keySet().stream().map(t -> {
List<String> categoryGroupList = ids.get(t).stream().toList();
Optional<EventCategoryEntity> f = flux1.toStream().filter(pp -> pp.getId().equals(t)).findFirst();
return new EventCategoryDTO(f.get().getId(), f.get().getCategoryName(), categoryGroupList);
}).toList())
.subscribe(result -> System.out.println(result.toString()));
}
Output:
[EventCategoryDTO(id=87108493-4fc1-4b12-8ffc-e10aa039fc39,
categoryName=soccer, categoryGroup=[team, ball]),
EventCategoryDTO(id=57108499-4fc1-4b52-8ffc-e11aa039fc85,
categoryName=soccer, categoryGroup=[tennis])]
https://projectreactor.io/docs/core/release/api/reactor/core/publisher/Flux.html#collectMultimap-java.util.function.Function-java.util.function.Function-

Related

Add a list of customers to an object in Spring

I have this object that I'm retrieving from antoher microservice.
#Service
public class WebClientService {
public Mono<CuCoPerson> getCuCoPerson(Integer cucoId, String GS_AUTH_TOKEN) {
WebClient webClient = WebClient.create();
return webClient.get()
.uri(GET_RELATION_BY_ID + cucoId)
.header("Accept", "application/json")
.header("Authorization", GS_AUTH_TOKEN)
.retrieve()
.bodyToMono(CuCoPerson.class)
.map(cuCoPerson -> {
List<CustomerRelation> matches = cuCoPerson.getRelatedCustomers()
.stream()
.filter(relation -> relation.getSystemId().equals(400) || relation.getSystemId().equals(300) || relation.getSystemId().equals(410))
.filter(relation -> relation.getCustomerId().contains("F"))
.collect(Collectors.toList());
cuCoPerson.setRelatedCustomers(matches);
return cuCoPerson;
});
}
The controller is as follows:
#GetMapping("/getCucoId/{cucoId}")
public Mono<CuCoPerson> getCucoRelationById(#PathVariable Integer cucoId, #RequestHeader(value="Authorization") String GS_AUTH_TOKEN) {
return webClientService.getCuCoPerson(cucoId, GS_AUTH_TOKEN);
}
It returns a list of related customers like this:
{
"id": 1,
"relatedCustomers": [
{
"customerId": "xxx",
"systemId": 999
}
]
}
And now I need to add this list of customers to my PeopleDTO class which is as follows:
public class PeopleDTO {
private String processType;
private String operation;
private String entity;
private String entityType;
private Long id;
private Document document;
#Getter
#Setter
class Customer {
private String systemId;
private String customerId;
}
private List<Customer> customers;
}
UPDATE:
Here I'm hardcoding my PeopleDTO just as an example:
public PeopleDTO createPeople(Long id) {
PeopleDTO people = new PeopleDTO();
people.setProcessType("ONLINE");
people.setOperation("UPDATE");
people.setEntity("DOCUMENT");
people.setEntityType("DOCUMENT");
people.setIdCuco(id);
people.setDocument(new Document());
people.setCustomers(......);
}
So the result should be something like this:
{
"type": "ONLINE",
"operation": "UPDATE",
"id": 1,
"entity": "DOCUMENT",
"entityType": "NIE",
"documents": {
"id": 1,
"additionals": {
"issuing_authority": "Spain",
"country_doc": "ES",
"place_of_birth": "",
"valid_from": "1995-08-09",
"valid_to": "0001-01-01"
},
"code": "X12345",
"typeDocument": "NIE"
},
"id": 1,
"relatedCustomers": [
{
"customerId": "xxx",
"systemId": 999
}
]
}
The controller that supposed to retrieve this info is:
#GetMapping("getId/{cucoId}")
public PeopleDTO getFullPeople(#PathVariable Long id) {
return webClientService.createPeople(id);
}
How should I set the customers in here?

Creating the Base Entity class in relational entity classes

The json below is what was sent to me, when I findByPinCode. I have created relations between them in the following accordance with the json answer. Here are the relationships.
{
"RequestIdentifier": "00000000-0000-0000-0000-000000000000",
"Status": {
"Name": "string",
"Code": 0,
"Message": "string"
},
"Response": {
"Person": {
"Pin": "string",
"LastName": "string",
"FirstName": "string",
"FatherName": "string",
"BirthDate": "string"
},
"Company": {
"Voen": "string",
"Name": "string",
"PersonType": "string",
"Persons": [
{
"Pin": "string",
"LastName": "string",
"FirstName": "string",
"FatherName": "string",
"BirthDate": "string"
}
]
},
"Farms": [
{
"Id": 0,
"Name": "string",
"Fields": [
{
"VillageName": "string",
"DocType": "string",
"FieldAmount": 0,
"Unit": "string",
"Plants": [
{
"Name": "string",
"FieldAmount": 0,
"Unit": "string"
}
]
}
],
"Animals": [
{
"Sort": "string",
"Count": 0
}
],
"Bees": [
{
"Sort": "string",
"Count": 0
}
]
}
]
}
}
(One)Company To (Many)Persons
(One)FarmInfo To (Many)FarmFields
(One)FarmFields To (Many)Plants
(One)FarmInfo To (Many)Animals
(One)FarmInfo To (Many)Bees
and thus converting them to my dto class first. Then I want to convert them to my entity classes and persist them completely to the database.
This is my DTO class.
#Data
#NoArgsConstructor
#AllArgsConstructor
public class FarmInfoMainResult {
#JsonProperty(value = "RequestIdentifier")
private String requestIdentifier;
#JsonProperty(value = "Status")
private ResponseStatus status;
#JsonProperty(value = "Response")
private FarmInfoData response;
}
and this is my business logic layer of method, which I want to that in here convertint the dto class to the BaseEntity class and at the end of I want to persist BaseEntity class to the database.
#Override
public ResponseEntity<FarmInfoMainResult> findFarmInfoByPin(String pin, String username, String branchCode) {
String requestIdentifier = UUID.randomUUID().toString();
ResponseEntity<FarmInfoMainResult> farmInfoPinServiceResponse = clientUtility.getForObject(farmInfoForPinUrl + pin, requestIdentifier, FarmInfoMainResult.class);
System.out.println("farmInfoPinServiceResponse " + farmInfoPinServiceResponse.getBody());
/*
Here are I want to convert farmInfoPinServiceResponse variable to the my Base Entity class and so persist it to the database, so that
thus, values will be automatically added to them as they are related to each other in other relational databases.
*/
return farmInfoPinServiceResponse;
}
#Entity
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class BaseEntity {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String requestIdentifier;
#OneToOne(cascade = CascadeType.ALL)
private Status status;
#OneToOne(cascade = CascadeType.ALL)
private Response response;
}
But I am getting the following error in my Response class. basic' attribute type should not be a container
#Entity
#Data
#Builder
#NoArgsConstructor
#AllArgsConstructor
public class Response {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private PersonFarmInfo personFarmInfo;
private CompanyFarmInfo companyFarmInfo;
private FarmInfo farmInfo;
private FarmFieldInfo farmFieldInfo;
private FarmPlantInfo farmPlantInfo;
private FarmAnimalInfo farmAnimalInfo;
private FarmBeeInfo farmBeeInfo;
#OneToOne(mappedBy = "response")
private BaseEntity baseEntity;
}
If I don't create main entity class, there will be a situation like this. I will add the properties of each class that is in the dto to the properties of each of my entity class and print them to the database. But by insert to a single entity class I want others to be affected as well. I wanted to solve the issue by creating a main entity class like this, but I'm getting the following error.
As I said at the beginning, the codes below do this by separating them into parts. These codes my old version codes.
#Override
public ResponseEntity<FarmInfoMainResult> findFarmInfoByPin(String pin, String username, String branchCode) {
String requestIdentifier = UUID.randomUUID().toString();
ResponseEntity<FarmInfoMainResult> farmInfoPinServiceResponse = clientUtility.getForObject(farmInfoForPinUrl + pin, requestIdentifier, FarmInfoMainResult.class);
System.out.println("farmInfoPinServiceResponse " + farmInfoPinServiceResponse.getBody());
saveFarmInfoPin(farmInfoPinServiceResponse.getBody(), username, branchCode, pin);
return farmInfoPinServiceResponse;
}
Here I am sending the object stored in dto to my saveFarmInfoPin method.Then this method works. Here, my method saves all my object values stored in dto separately.
private void saveFarmInfoPin(FarmInfoMainResult farmInfoMainResult, String username, String branchcode, String pin) {
// try {
if (farmInfoMainResult.getResponse() != null) {
saveFarmInfoPersonPin(farmInfoMainResult.getResponse().getPerson(), farmInfoMainResult.getRequestIdentifier(), username, branchcode, pin);
saveFarmInfoCompanyPin(farmInfoMainResult.getResponse().getCompany(), farmInfoMainResult.getRequestIdentifier(), username, branchcode);
saveFarminfo(farmInfoMainResult.getResponse().getFarms());
/* } catch (Exception e) {
e.printStackTrace();
}
*/
}
}
Finally, my following methods divide each of my dto objects into parts, first converting them to my entity class, and then adding them to the database via repository.
private void saveFarmInfoPersonPin(FarmInfoPerson farmInfoPersonDto, String requestIdentifier, String username, String branchCode, String pin) {
if (farmInfoPersonDto != null) {
FarmPersonInfo newFarmInfoPerson = new FarmPersonInfo();
newFarmInfoPerson.setRequestIdentifier(requestIdentifier);
newFarmInfoPerson.setBranchCode(branchCode);
newFarmInfoPerson.setUsername(username);
newFarmInfoPerson.setPin(pin);
newFarmInfoPerson.setPin(farmInfoPersonDto.getPin());
newFarmInfoPerson.setFatherName(farmInfoPersonDto.getFatherName());
newFarmInfoPerson.setFirstName(farmInfoPersonDto.getFirstName());
newFarmInfoPerson.setBirthDate(farmInfoPersonDto.getBirthDate());
personFarmInfoRepository.save(newFarmInfoPerson);
}
}
private void saveFarmInfoCompanyPin(FarmInfoCompany farmInfoCompany, String requestIdentifier, String username, String branchCode) {
List<FarmPersonInfo> newFarmInfoPersonList = new ArrayList<>();
if (farmInfoCompany != null) {
FarmCompanyInfo newCompanyFarmInfo = new FarmCompanyInfo();
newCompanyFarmInfo.setName(farmInfoCompany.getName());
newCompanyFarmInfo.setRequestIdentifier(requestIdentifier);
newCompanyFarmInfo.setUsername(username);
newCompanyFarmInfo.setBranchCode(branchCode);
newCompanyFarmInfo.setPersonType(farmInfoCompany.getPersonType());
newCompanyFarmInfo.setVoen(farmInfoCompany.getVoen());
// CompanyFarmInfo companyFarmInfo = companyFarmInfoRepository.save(newCompanyFarmInfo);
for (FarmInfoPerson farmInfoPerson : farmInfoCompany.getPersons()) {
FarmPersonInfo personInfo = new FarmPersonInfo();
personInfo.setPin(farmInfoPerson.getPin());
personInfo.setFatherName(farmInfoPerson.getFatherName());
personInfo.setFirstName(farmInfoPerson.getFirstName());
personInfo.setBirthDate(farmInfoPerson.getBirthDate());
personInfo.setFarmCompanyInfo(newCompanyFarmInfo);
newFarmInfoPersonList.add(personInfo);
}
personFarmInfoRepository.saveAll(newFarmInfoPersonList);
}
}
private void saveFarminfo(List<FarmInfoFarm> farmInfoFarms) {
List<FarmFieldInfo> newFarmFieldInfoList = new ArrayList<>();
List<FarmAnimalInfo> newFarmAnimalInfoList = new ArrayList<>();
List<FarmBeeInfo> newFarmBeeInfoList = new ArrayList<>();
List<FarmPlantInfo> newFarmPlantInfoList = new ArrayList<>();
for (FarmInfoFarm farmInfoFarm : farmInfoFarms) {
FarmInfo newFarmInfo = new FarmInfo();
newFarmInfo.setName(farmInfoFarm.getName());
newFarmInfo.setFarmInfoId(farmInfoFarm.getId());
FarmInfo farmInfo = farmInfoRepository.save(newFarmInfo);
for (FarmInfoField farmInfoField : farmInfoFarm.getFields()) {
FarmFieldInfo newFarmFieldInfo = new FarmFieldInfo();
newFarmFieldInfo.setVillageName(farmInfoField.getVillageName());
newFarmFieldInfo.setDocType(farmInfoField.getDocType());
newFarmFieldInfo.setFieldAmount(farmInfoField.getFieldAmount());
newFarmFieldInfo.setUnit(farmInfoField.getUnit());
newFarmFieldInfo.setFarmInfo(farmInfo);
newFarmFieldInfoList.add(newFarmFieldInfo);
for (FarmInfoPlant farmInfoPlant : farmInfoField.getPlants()) {
FarmPlantInfo newfarmPlantInfo = new FarmPlantInfo();
newfarmPlantInfo.setName(farmInfoPlant.getName());
newfarmPlantInfo.setFieldAmount(farmInfoPlant.getFieldAmount());
newfarmPlantInfo.setUnit(farmInfoPlant.getUnit());
newfarmPlantInfo.setFarmFieldInfo(newFarmFieldInfo);
newFarmPlantInfoList.add(newfarmPlantInfo);
}
farmPlantInfoRepository.saveAll(newFarmPlantInfoList);
}
farmFieldInfoRepository.saveAll(newFarmFieldInfoList);
for (FarmInfoAnimal farmInfoAnimal : farmInfoFarm.getAnimals()) {
FarmAnimalInfo newFarmAnimalInfo = new FarmAnimalInfo();
newFarmAnimalInfo.setCount(farmInfoAnimal.getCount());
newFarmAnimalInfo.setSort(farmInfoAnimal.getSort());
newFarmAnimalInfo.setFarmInfo(farmInfo);
newFarmAnimalInfoList.add(newFarmAnimalInfo);
}
farmAnimalInfoRepository.saveAll(newFarmAnimalInfoList);
for (FarmInfoBee farmInfoBee : farmInfoFarm.getBees()) {
FarmBeeInfo newfarmBeeInfo = new FarmBeeInfo();
newfarmBeeInfo.setCount(farmInfoBee.getCount());
newfarmBeeInfo.setSort(farmInfoBee.getSort());
newfarmBeeInfo.setFarmInfo(farmInfo);
newFarmBeeInfoList.add(newfarmBeeInfo);
}
farmBeeInfoRepository.saveAll(newFarmBeeInfoList);
}
}
But as I said, instead of separating them all into separate-parts, can I add all of these objects to my main entity class and bring all these particles together through just one method?
I'm thinking of something like this, now I will use jackson to convert all the values in the json value I have received to the classes it belongs to, then I will add them to my main class and finally add my main class to my database. Since the main class will already have all the relations in itself, I think that all of them will be affected by doing this operation once.

Put method using a mapped class (use setters for specified parameter) - Spring boot API

I'm trying to make a PUT request for an object using only one function for all parameters. Let's say I have this object structure (JSON):
{
"id": 3,
"name": "test",
"dominio": "dom",
"altas": "6",
"bajas": "2",
"default_group": [
{
"idRef": 1,
"name": "Users",
"path": "OU=es"
}
],
"office": [
{
"idRef": 1,
"title": "Intern",
"name": "CN=Office license",
"path": "OU=licenseOffice"
},
{
"idRef": 2,
"title": "Specialist",
"name": "CN=Office License F3",
"path": "OU=LicenseGroupF"
}
]
}
I managed to do this for a GET Request using a Map function with the getters of the class.
To do this, I passed the attribute name in the HTTP request using a GET Request:
Map<String, Function<Compania, Object>> mapCompania = Map.of(
"name", Compania::getName,
"dominio", Compania::getDominio,
"altas", Compania::getAltas,
"bajas", Compania::getBajas,
"default_group", Compania::getDefault_group,
"office", Compania::getOffice
);
Function<Compania, Object> retriever = mapCompania.get(fieldName);
But now, I can't find a way to implement this same thing but in order to use the setter methods. Something like:
PUT localhost/myClass/3/name --> it uses MyClass.setName(input...)
Or:
PUT localhost/myClass/3/office --> it uses MyClass.setOffice(Object office)
Could anyone help me to achieve this? Thank you very much
Assuming that Compania is as follows:
public class Compania {
private Object name;
private Object dominio;
private Object altas;
private Object bajas;
private Object default_group;
private Object office;
public Object getName() {
return name;
}
public void setName(Object name) {
this.name = name;
}
public Object getDominio() {
return dominio;
}
public void setDominio(Object dominio) {
this.dominio = dominio;
}
public Object getAltas() {
return altas;
}
public void setAltas(Object altas) {
this.altas = altas;
}
public Object getBajas() {
return bajas;
}
public void setBajas(Object bajas) {
this.bajas = bajas;
}
public Object getDefault_group() {
return default_group;
}
public void setDefault_group(Object default_group) {
this.default_group = default_group;
}
public Object getOffice() {
return office;
}
public void setOffice(Object office) {
this.office = office;
}
}
The code below should do the trick:
Map<String, BiConsumer<Compania, Object>> mapCompaniaSetters = Map.of(
"name", Compania::setName,
"dominio", Compania::setDominio,
"altas", Compania::setAltas,
"bajas", Compania::setBajas,
"default_group", Compania::setDefault_group,
"office", Compania::setOffice
);
BiConsumer<Compania, Object> setter = mapCompaniaSetters.get(fieldName);
We can test this as follows to check that it actually works:
public static void main(String[] args) {
Map<String, BiConsumer<Compania, Object>> mapCompaniaSetters = Map.of(
"name", Compania::setName,
"dominio", Compania::setDominio,
"altas", Compania::setAltas,
"bajas", Compania::setBajas,
"default_group", Compania::setDefault_group,
"office", Compania::setOffice
);
BiConsumer<Compania, Object> setter = mapCompaniaSetters.get("name");
Compania compania = new Compania();
System.out.println("Empty Compania: " + compania);
setter.accept(compania, "Test");
System.out.println("Compania with Name: " + compania);
}

rest api - PUT method does not consume the data that GET method fetches

I obtain data with GET method and try to fed them to PUT method.
And I get a bad request error.
But when I edit the JSON as below then everithing works fine.
So why does the first JSON not work?
Controller class:
#RestController
#RequestMapping("/api")
public class FileController {
private final FileService fileService;
private final DocService docService;
private final DraftFileToPresentationConverter draftFileToPresentationConverter;
#Autowired
private DocFileRelationRepository docFileRelationRepository;
#Autowired
public FileController(FileService fileService,
DocService docService,
DraftFileToPresentationConverter draftFileToPresentationConverter) {
this.fileService = fileService;
this.docService = docService;
this.draftFileToPresentationConverter = draftFileToPresentationConverter;
}
#GetMapping("/docs/files/{id}")
public ResponseEntity<FilePresentation> getDraftFile(#PathVariable Long id) {
DraftFile file = fileService.getFile(id);
FilePresentation filePresentation = draftFileToPresentationConverter.convert(file);
return new ResponseEntity<>(filePresentation, HttpStatus.OK);
}
#PutMapping("/docs/files/{id}")
public ResponseEntity<FilePresentation> updateDraftFile(#RequestBody FilePresentation filePresentation) {
fileService.update(draftFileToPresentationConverter.convert(filePresentation));
return new ResponseEntity<>(filePresentation, HttpStatus.OK);
}
DTO:
#Data
public class FilePresentation {
private Long id;
private States state;
private String name;
private String user;
private Date dateUpload;
private Long lenght;
private IdRef document;
private IdRef judgeDoc;
public String getSize()
{
Double result = Double.valueOf(lenght/1024.0/1024.0);
if(result<1)
{
result = Double.valueOf(lenght/1024.0);
if(result<1)
{
return (lenght + " байт");
}
return (result.intValue() + " Кбайт");
}
return (result.intValue() + " Мбайт");
}
}
Troublesome class:
#Data
public class IdRef {
public IdRef(Long id) {
this.id = id;
}
private Long id;
}
JSON that I get with GET method and try to fed to PUT method (and get 400 Bad Request):
{
"id": 21,
"state": "DRAFT",
"name": "DNS-list.tiff",
"user": "JSmith",
"dateUpload": null,
"lenght": 28,
"document": {
"id": 141
},
"judgeDoc": null,
"size": "28 байт"
}
JSON that DOES work
{
"id": 21,
"state": "DRAFT",
"name": "DNS-list.tiff",
"user": "JSmith",
"dateUpload": null,
"lenght": 28,
"document": 141,
"judgeDoc": null,
"size": "28 байт"
}
Try to update RequestBody with #PathVariable
The constructor in IdRef was the reason.
I removed the constructor and it works fine now, my controller consumes the first JSON without errors.

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

Categories