Introdução
A estrutura de um típico conjunto de operações básicas de serviços da Web em instâncias de entidades (objetos) é CRUD ( C reate, R ead, U pdate e D elete). Os métodos HTTP POST, GET, PUT e DELETE correspondem a essas operações em REST. Mas muitas vezes o desenvolvedor precisa alterar parcialmente o objeto correspondente ao método HTTP PATCH. Seu significado é alterar no lado do servidor apenas os campos do objeto que foram passados na solicitação. Há várias razões para isto:
um grande número de campos em essência;
alta probabilidade de mudança simultânea do mesmo objeto sob alta carga, como resultado não apenas os campos modificados serão sobrescritos;
impossibilidade ou maior complexidade de alterar campos em vários ou todos os objetos no armazenamento (atualização em massa);
Essas e, possivelmente, outras razões induzem o desenvolvedor a implementar uma pilha de operações para modificação parcial do objeto.
Vamos considerar as opções usadas com mais frequência para resolver o problema de atualização parcial.
Usando um controlador regular e DTO
Uma das implementações de método PATCH mais comuns. No controlador, o objeto de entrada é desserializado em um DTO regular e, mais adiante na pilha de camadas do aplicativo, considera-se que todos os campos no DTO com um valor nulo não podem ser processados.
As vantagens deste método incluem a "familiaridade" com a implementação.
- null
( null
).
DTO . , . ObjectMapper
(/ POJO, @JsonInclude(Include.NON_NULL) ) , MapStruct, .
Map<String, Object> POJO
Map<String, Object>
. JSON . , , ( IDE).
null
.
: , , , , runtime( ).
JSON Patch JSON Merge Patch
JSON Patch JSON Merge Patch . Java EE , : JsonPatch JsonMergePatch. , json-patch. Michael Scharhag REST: Partial updates with PATCH.
: , , , , , , .
, DTO , , , , etc.
Partial Update library
: DTO Map<String, Object>
" ".
ChangeLogger ChangeLoggerProducer.
ChangeLoggerProducer
"" POJO, ChangeLogger
, Map<String, Object>
.
POJO:
public class UserModel {
private String login;
private String firstName;
private String lastName;
private String birthDate;
private String email;
private String phoneNumber;
}
@ChangeLogger
public class UserDto extends UserModel {
}
"":
ChangeLoggerProducer<UserDto> producer = new ChangeLoggerProducer<>(UserDto.class);
UserDto user = producer.produceEntity();
user.setLogin("userlogin");
user.setPhoneNumber("+123(45)678-90-12");
Map<String, Object> changeLog = ((ChangeLogger) user).changelog();
/*
changeLog in JSON notation will contains:
{
"login": "userlogin",
"phoneNumber": "+123(45)678-90-12"
}
*/
"" : Set<String>
, Map<String, Object> changelog()
, , , . , , ChangeLogger
, Map<String, Object> changelog()
.
/ "" ChangeLoggerAnnotationIntrospector
. Annotation Introspector ObjectMapper
. "" , @ChangeLogger
Map<String, Object> changelog()
. ObjectMapper
ChangeLoggerAnnotationIntrospector
.
:
ObjectMapper mapper = new ObjectMapper.setAnnotationIntrospector(new ChangeLoggerAnnotationIntrospector());
ChangeLoggerProducer<UserDto> producer = new ChangeLoggerProducer<>(UserDto.class);
UserDto user = producer.produceEntity();
user.setLogin("userlogin");
user.setPhoneNumber("+123(45)678-90-12");
String result = mapper.writeValueAsString(user);
/*
result should be equal
"{\"login\": \"userlogin\",\"phoneNumber\": \"+123(45)678-90-12\"}"
*/
:
ObjectMapper mapper = new ObjectMapper.setAnnotationIntrospector(new ChangeLoggerAnnotationIntrospector());
String source = "{\"login\": \"userlogin\",\"phoneNumber\": \"+123(45)678-90-12\"}";
UserDto user = mapper.readValue(source, UserDto.class);
Map<String, Object> changeLog = ((ChangeLogger) user).changelog();
/*
changeLog in JSON notation will contains:
{
"login": "userlogin",
"phoneNumber": "+123(45)678-90-12"
}
*/
ObjectMapper
ChangeLoggerAnnotationIntrospector
JSON . DTO, Model, Entity "". Partial Update Example.
Partial Update library , . , runtime.
:
" ", DTO, Model, Entity;
Spring, / "" DTO ( ),
ChangeLoggerAnnotationIntrospector
ObjectMapper
;
SQL/HQL bulk update ;
.
O formato deste artigo não permite examinar mais de perto a infraestrutura para a criação de mapeadores e mostrar o uso da biblioteca em uma pilha de aplicativo típica. No futuro, posso analisar o exemplo de atualização parcial em mais detalhes e prestar mais atenção à descrição da implementação interna da biblioteca.