Home > database >  Java - RestAPI - Patch not working efficiently
Java - RestAPI - Patch not working efficiently

Time:11-06

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); 
}
  • Related