Add a list of customers to an object in Spring - java

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?

Related

Map Flux into business DTO with list

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-

Get and Post Object including list of another Object

I have 3 Models which belong together:
Device
Person
Inspection
An Inspection could have many devices and one person.
I realized these relations using a separate table:
#Entity
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#Table(name = "ACTION_INSPECTION")
public class ActionInspection implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column
private Long actionInspectionId;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "personId")
private Person person;
#NotNull
#JsonProperty("devices")
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "deviceId")
private Device device;
#NotNull
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "inspectionId")
private Inspection inspection;
//endregion
//constructors and getters & setters
}
Get- and Post-Methods of ActionInspectionController:
#GetMapping(value = "/all")
public List<ActionInspection> getAllActionInspections() {
return actionInspectionRepository.findAll();
}
#GetMapping(value = "")
public ResponseEntity<?> getActionInspectionById(#RequestParam long actionInspectionId ) {
Optional<ActionInspection> optionalActionInspection = actionInspectionRepository.findById(actionInspectionId);
ResponseEntity<?> result;
if (optionalActionInspection.isPresent()) {
ActionInspection actionInspection = optionalActionInspection.get();
result = new ResponseEntity<ActionInspection>(actionInspection, HttpStatus.OK);
}
else {
result = new ResponseEntity<String>(String.format("ActionInspection with Id %d doesn't exist", actionInspectionId), HttpStatus.NOT_FOUND);
}
return result;
}
#Transactional
#PostMapping(value = "")
public ResponseEntity<?> insertActionInspection(#Valid #RequestBody ActionInspection actionInspection, BindingResult bindingResult) {
ResponseEntity<?> result = null;
String errorMessage = "";
boolean error = false;
Optional<Person> optionalPerson = personRepository.findById(actionInspection.getPerson().getPersonId());
Optional<Device> optionalDevice = deviceRepository.findById(actionInspection.getDevice().getDeviceId());
if (optionalPerson.isPresent())
actionInspection.setPerson(optionalPerson.get());
else
result = new ResponseEntity<String>("Person not found", HttpStatus.NOT_FOUND);
if (!optionalDevice.isPresent())
actionInspection.setDevice(optionalDevice.get());
else
result = new ResponseEntity<String>("Device not found", HttpStatus.NOT_FOUND);
try {
inspectionRepository.save(actionInspection.getInspection());
actionInspectionRepository.save(actionInspection);
result = new ResponseEntity<ActionInspection>(actionInspection, HttpStatus.CREATED);
}
catch (Exception e) {
e.printStackTrace();
error = bindingResult.hasErrors();
errorMessage = bindingResult.toString();
result = new ResponseEntity<String>(errorMessage, HttpStatus.INTERNAL_SERVER_ERROR);
}
return result;
}
}
So, creating a new ActionInspection includes creating a new Inspection as well if needed.
Using the GetMethod to list all ActionInspections I get this:
[
{
"actionInspectionId": 1,
"person": {
"personId": 1,
"lastname": "Maier",
"firstname": "Sepp"
},
"inspection": {
"inspectionId": 3,
"inspectionDate": "2021-12-31",
"inspectionState": 2,
"inspectionInterval": 1.0
},
"devices": {
"deviceId": 3,
"deviceName": "Kaffeemaschine",
"deviceState": 2,
"deviceDescription": "praktisch"
}
},
{
"actionInspectionId": 2,
"person": {
"personId": 1,
"lastname": "Maier",
"firstname": "Sepp"
},
"inspection": {
"inspectionId": 3,
"inspectionDate": "2021-12-31",
"inspectionState": 2,
"inspectionInterval": 1.0
},
"devices": {
"deviceId": 2,
"deviceName": "Farbdrucker",
"deviceState": 1,
"deviceDescription": "sehr leise"
}
}
]
But I need to get and post Json which includes a list of all devices which belongs to the same inspection(Id):
[
{
"person": {
"personId": 1,
"lastname": "Maier",
"firstname": "Sepp"
},
"inspection": {
"inspectionId": 3,
"inspectionDate": "2021-12-31",
"inspectionState": 2,
"inspectionInterval": 1
},
"devices": [
{
"deviceId": 3,
"deviceName": "Kaffeemaschine",
"deviceState": 2,
"deviceDescription": "praktisch"
},
{
"deviceId": 2,
"deviceName": "Farbdrucker",
"deviceState": 1,
"deviceDescription": "sehr leise"
}
]
}
]
Is there a way I can realize this?
Many thanks in advance for every input I'll get - also for criticism (no matter if good or bad).

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.

RestTemplate Map JSON array to list of objects

I'm having trouble mapping the environments LetakTandaTanganResponseDto in the below JSON response output into a list of LetakTandaTanganResponseDto objects using RestTemplate.
I have a response from URL which looks like:
{
"code": "00",
"desc": "SUCCESS",
"body": [
{
"id": 71,
"createdate": null,
"lx": "104",
"ly": "632",
"page": 1,
"prfKe": 0,
"rx": "260",
"ry": "632",
"ttdKe": 1,
"formatItemId": null,
"formatPdfId": 10
},
{
"id": 72,
"createdate": null,
"lx": "485",
"ly": "629",
"page": 1,
"prfKe": 0,
"rx": "692",
"ry": "629",
"ttdKe": 2,
"formatItemId": null,
"formatPdfId": 10
},
{
"id": 73,
"createdate": null,
"lx": "585",
"ly": "729",
"page": 1,
"prfKe": 0,
"rx": "792",
"ry": "729",
"ttdKe": 3,
"formatItemId": null,
"formatPdfId": 10
}
]
}
RestTemplate code.
ResponseEntity<List<LetakTandaTanganResponseDto>> letakTTDResponse = restTemplate.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<List<LetakTandaTanganResponseDto>>() {
});
if (letakTTDResponse != null && letakTTDResponse.hasBody()) {
listletakTTD = letakTTDResponse.getBody();
}
return listletakTTD;
Where as, if I happen to use a custom Value object, somethings like:
#Data
#ToString
public class LetakTandaTanganResponseDto {
public String code;
public String desc;
public Body body;
#Data
#ToString
public class Body {
public Long id;
public Integer ttd_ke;
public Integer page;
public String lx;
public String ly;
public String rx;
public String ry;
public String createdate;
public Integer prfKe;
public Long formatItemId;
public Long formatPdfId ;
}
}
Can you help how to the JSON list structure mentioned above can be mapped to an object?
Try changing your response class as per the json response
public class LetakTandaTanganResponseDto {
public String code;
public String desc;
public List<Body> body;
// ...
}
and your response would be
ResponseEntity<LetakTandaTanganResponseDto> letakTTDResponse = restTemplate.exchange(uri, HttpMethod.GET, entity, new ParameterizedTypeReference<LetakTandaTanganResponseDto>() {
});
if (letakTTDResponse != null && letakTTDResponse.hasBody()) {
listletakTTD.setBody( letakTTDResponse.getBody());
}
return listletakTTD;

Categories