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
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-
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).
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);
}
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.
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;