I've a small problem with my method using protocol PATCH in my RestController, I'm creating an object Warehouse.
1st I'm creating it via POST:
{
"location" : "Paris",
"maxCapacity" : "200"
}
Result:
[
{
"id": 1,
"location": "Paris",
"currentCapacity": 0,
"maxCapacity": 200,
"cargosList": [],
"status": "EMPTY"
}
]
When for example, PATCHing only field location:
{
"location" : "New York"
}
And when reading with GET:
[
{
"id": 1,
"location": "New York",
"currentCapacity": 0,
"maxCapacity": null,
"cargosList": [],
"status": "EMPTY"
}
]
Why the field maxCapacity have been changed to null although my PATCH request was only on field location?
My Entity:
package net.erickcaron.warehouseapplicationapi.models;
import com.fasterxml.jackson.annotation.JsonManagedReference;
import lombok.*;
import javax.persistence.*;
import java.util.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity(name = "warehouses")
public class Warehouse {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String location;
private Integer currentCapacity = 0;
private Integer maxCapacity;
@OneToMany
@JsonManagedReference
private List<Cargo> cargosList = new ArrayList<>();
@Enumerated(value = EnumType.STRING)
private WarehouseStatus status = WarehouseStatus.EMPTY;
}
My RestController:
package net.erickcaron.warehouseapplicationapi.rest;
import net.erickcaron.warehouseapplicationapi.models.Warehouse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import net.erickcaron.warehouseapplicationapi.services.WarehouseService;
import javax.transaction.Transactional;
import java.util.List;
@Transactional
@RestController
@RequestMapping("/warehouses")
public class WarehouseRestController {
@Autowired
private WarehouseService warehouseService;
@PostMapping
public Integer create(@RequestBody Warehouse warehouse){
return warehouseService.create(warehouse);
}
@GetMapping("/{id}")
public Warehouse findById(@PathVariable Integer id){
return warehouseService.findById(id);
}
@GetMapping
public List<Warehouse> findAll(){
return warehouseService.findAll();
}
@PatchMapping("/{id}") //TODO not working!
public void partialUpdate(@PathVariable Integer id, @RequestBody Warehouse warehouse){
warehouseService.partialUpdate(id, warehouse);
}
@DeleteMapping("/{id}")
public void deleteById(@PathVariable Integer id){
warehouseService.deleteById(id);
}
@PatchMapping("/{warehouseId}/cargos/{cargoId}")
public void addCargoToWarehouse(@PathVariable Integer warehouseId, @PathVariable Integer cargoId){
warehouseService.addCargoToWarehouse(warehouseId, cargoId);
}
}
Thanks for any help, Regards, Erick
CodePudding user response:
Use a mapper
to update your Entity and then persist it again. I can more than recommend MapStruct!
You can create a Mapper
this way:
@Mapper
public interface WarehouseMapper {
// Ignore null Values
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateWarehouse(Warehouse updatedWarehouse, @MappingTarget Warehouse oldWarehouse);
}
Then you can get your mapper in the partialUpdate()
function and use it this way:
public void partialUpdate(Integer id, Warehouse updatedWarehouse)
{
Warehouse oldWarehouse = findById(id);
WarehouseMapper mapperInstance = Mappers.getMapper( WarehouseMapper.class );
mapperInstance.updateWarehouse(updatedWarehouse, oldWarehouse); // Maps the NON NULL fields of updatedWarehouse to oldWarehouse fields
warehouseRepository.save(oldWarehouse);
}
OR
Do the mapping yourself and do not use any external dependencies:
public void partialUpdate(Integer id, Warehouse updatedWarehouse)
{
Warehouse oldWarehouse = findById(id);
if(updatedWarehouse.getLocation() != null)
{
oldWarehouse.setLocation(updatedWarehouse.getLocation());
}
// ... And so on for each field
warehouseRepository.save(oldWarehouse);
}