How to distinguish between null and not provided values for partial updates in Spring Rest Controller

Danilo Cianciulli :

I'm trying to distinguish between null values and not provided values when partially updating an entity with PUT request method in Spring Rest Controller.

Consider the following entity, as an example:

@Entity
private class Person {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    /* let's assume the following attributes may be null */
    private String firstName;
    private String lastName;

    /* getters and setters ... */
}

My Person repository (Spring Data):

@Repository
public interface PersonRepository extends CrudRepository<Person, Long> {
}

The DTO I use:

private class PersonDTO {
    private String firstName;
    private String lastName;

    /* getters and setters ... */
}

My Spring RestController:

@RestController
@RequestMapping("/api/people")
public class PersonController {

    @Autowired
    private PersonRepository people;

    @Transactional
    @RequestMapping(path = "/{personId}", method = RequestMethod.PUT)
    public ResponseEntity<?> update(
            @PathVariable String personId,
            @RequestBody PersonDTO dto) {

        // get the entity by ID
        Person p = people.findOne(personId); // we assume it exists

        // update ONLY entity attributes that have been defined
        if(/* dto.getFirstName is defined */)
            p.setFirstName = dto.getFirstName;

        if(/* dto.getLastName is defined */)
            p.setLastName = dto.getLastName;

        return ResponseEntity.ok(p);
    }
}

Request with missing property

{"firstName": "John"}

Expected behaviour: update firstName= "John" (leave lastName unchanged).

Request with null property

{"firstName": "John", "lastName": null}

Expected behaviour: update firstName="John" and set lastName=null.

I cannot distinguish between these two cases, sincelastName in the DTO is always set to null by Jackson.

Note: I know that REST best practices (RFC 6902) recommend using PATCH instead of PUT for partial updates, but in my particular scenario I need to use PUT.

Demon Coldmist :

Actually,if ignore the validation,you can solve your problem like this.

   public class BusDto {
       private Map<String, Object> changedAttrs = new HashMap<>();

       /* getter and setter */
   }
  • First, write a super class for your dto,like BusDto.
  • Second, change your dto to extend the super class, and change the dto's set method,to put the attribute name and value to the changedAttrs(beacause the spring would invoke the set when the attribute has value no matter null or not null).
  • Third,traversal the map.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=427261&siteId=1