O problema costuma aparecer rápido em produção: o front envia só os campos que mudaram, o backend converte o DTO para entidade, faz save e, de repente, telefone, endereço ou status somem porque vieram null no payload. Por outro lado, se a sua dúvida é como aplicar mapstruct ignore null spring boot para atualizar uma entidade sem sobrescrever valores já persistidos, a resposta prática é esta: não crie uma entidade nova para salvar; carregue a entidade atual do banco e use um mapper com @MappingTarget e NullValuePropertyMappingStrategy.IGNORE. Ao mesmo tempo, isso resolve boa parte dos updates parciais e evita o patch manual repetitivo que cresce mal com o tempo. Para aprofundar essa decisao sem criar outra URL concorrente, o melhor complemento aqui e comparar com Guia completo de Spring Data JPA no Spring Boot sem dor.
Esse cenário é comum em APIs REST com PUT mal implementado, PATCH improvisado e DTOs compartilhados entre criação e atualização. Por outro lado, o bug nem sempre explode no mesmo dia. Ao mesmo tempo, às vezes, só aparece quando um usuário atualiza o nome e um campo sensível, que não estava na tela, vai para null sem ninguém perceber. Na prática, em sistemas com dados cadastrais, faturamento ou integrações, isso custa caro. Se fizer sentido comparar com outra abordagem do ecossistema Spring, veja comparar com JWT no Spring Security com Spring Boot: autenticação moderna passo a passo.
O ponto importante aqui é comparar duas abordagens que aparecem em projeto real: o patch manual no service, cheio de ifs, contra um mapper configurado para ignorar null. Por outro lado, as duas funcionam. Ao mesmo tempo, a diferença é manutenção, previsibilidade e o quanto sua regra de atualização continua legível depois de seis meses. Depois de ajustar esse trecho, o proximo passo natural e seguir para Ia para programadores java backend exemplo: evite erros.
Mapstruct ignore null spring boot: secao pratica com codigo completo
Na pratica, um exemplo enxuto ajuda a sair da teoria e evitar erro comum de producao quando o projeto cresce. Depois de ajustar esse trecho, o proximo passo natural e seguir para Spring Boot Health Check Actuator Monitoramento sem falhas.
@RestController
@RequestMapping("/api/exemplo")
public class ExemploController {
@GetMapping
public ResponseEntity<String> listar() {
return ResponseEntity.ok("ok");
}
}mapstruct ignore null spring boot: o que realmente resolve
MapStruct é ótimo quando você quer mapeamento explícito, compilado e sem reflection. Por outro lado, para atualização parcial, ele fica ainda mais útil porque permite aplicar dados de um DTO em uma entidade já carregada. Ao mesmo tempo, o detalhe que muda o jogo é não usar o mapper para criar uma entidade nova, e sim para modificar a instância existente. Depois de ajustar esse trecho, o proximo passo natural e seguir para aprofundar em como tratar exceções no spring boot com @controlleradvice e @exceptionhandler.
Na prática, a configuração que quase sempre interessa é ignorar propriedades null durante o update. Assim, se o cliente não enviar um campo, ou enviar null em um contexto onde null não deveria apagar dado, o valor atual da entidade permanece intacto.
Um mapper típico fica assim:
<code>@Mapper(componentModel = "spring")
public interface CustomerMapper {
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateEntityFromDto(CustomerUpdateDto dto, @MappingTarget Customer entity);
}
</code>O DTO pode ser simples:
<code>public class CustomerUpdateDto {
private String name;
private String email;
private String phone;
private String status;
// getters e setters
}
</code>E o service faz o fluxo correto:
<code>@Service
@RequiredArgsConstructor
public class CustomerService {
private final CustomerRepository customerRepository;
private final CustomerMapper customerMapper;
@Transactional
public CustomerResponseDto update(Long id, CustomerUpdateDto dto) {
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Cliente não encontrado"));
customerMapper.updateEntityFromDto(dto, customer);
Customer saved = customerRepository.save(customer);
return new CustomerResponseDto(saved.getId(), saved.getName(), saved.getEmail(), saved.getPhone(), saved.getStatus());
}
}
</code>Esse padrão é simples, legível e resolve o caso mais frequente: atualizar alguns campos sem destruir o resto. Por outro lado, se você quiser aprofundar a parte de persistência e comportamento da entidade gerenciada, faz sentido comparar com Guia completo de Spring Data JPA no Spring Boot sem dor.
mapstruct spring boot atualizar entidade sem sobrescrever null vs patch manual
O patch manual nasceu como solução rápida. Por outro lado, você pega a entidade, verifica campo por campo e atualiza só o que veio preenchido.
<code>@Transactional
public CustomerResponseDto updateManual(Long id, CustomerUpdateDto dto) {
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Cliente não encontrado"));
if (dto.getName() != null) {
customer.setName(dto.getName());
}
if (dto.getEmail() != null) {
customer.setEmail(dto.getEmail());
}
if (dto.getPhone() != null) {
customer.setPhone(dto.getPhone());
}
if (dto.getStatus() != null) {
customer.setStatus(dto.getStatus());
}
return new CustomerResponseDto(customer.getId(), customer.getName(), customer.getEmail(), customer.getPhone(), customer.getStatus());
}
</code>Funciona? Por outro lado, sim. Ao mesmo tempo, para dois ou três campos, sem drama. Na prática, o problema aparece quando a entidade cresce, o DTO muda, você tem vinte endpoints parecidos e a atualização parcial começa a se espalhar em vários services. Ainda assim, a chance de esquecer um campo, aplicar regra diferente em cada lugar ou gerar comportamento inconsistente sobe bastante.
Com MapStruct, a abordagem melhor costuma ser centralizar esse merge no mapper, deixando o service responsável pelo fluxo de negócio. Por outro lado, a abordagem pior, na maioria dos times, é duplicar if por if em vários pontos e torcer para ninguém quebrar o contrato sem perceber.
Comparando diretamente:
Patch manual: mais flexível no detalhe fino, bom para regra muito específica, mas vira código repetitivo com facilidade.
Mapper configurado: melhor para consistência, menos boilerplate e manutenção mais previsível, desde que você entenda bem os limites com relacionamentos, null intencional e coleções.
Em API real, eu prefiro MapStruct para campos simples e updates recorrentes. Por outro lado, quando existem regras muito específicas, por exemplo “null pode significar apagar em um campo, mas em outro significa ignorar”, parte da lógica precisa continuar explícita no service.
patch parcial mapstruct spring boot: implementação prática completa
Um exemplo mais próximo de produção ajuda mais do que uma classe isolada. Por outro lado, abaixo está um fluxo completo de update parcial em Spring Boot usando JPA, DTO, mapper e tratamento de regra básica.
Entidade
<code>@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String name;
@Column(nullable = false, unique = true)
private String email;
private String phone;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private CustomerStatus status;
// getters e setters
}
</code>DTO de atualização
<code>public class CustomerPatchDto {
private String name;
private String phone;
private CustomerStatus status;
// getters e setters
}
</code>Perceba uma decisão importante: nem todo campo precisa entrar no PATCH. Por outro lado, email, por exemplo, pode ter regra própria de alteração. Ao mesmo tempo, quando você separa melhor os DTOs, reduz ambiguidade e evita expor atualizações sensíveis sem querer.
Mapper
<code>@Mapper(componentModel = "spring")
public interface CustomerPatchMapper {
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void patch(CustomerPatchDto source, @MappingTarget Customer target);
}
</code>Repository
<code>public interface CustomerRepository extends JpaRepository<Customer, Long> {
}
</code>Service
<code>@Service
@RequiredArgsConstructor
public class CustomerAppService {
private final CustomerRepository repository;
private final CustomerPatchMapper patchMapper;
@Transactional
public Customer updatePartially(Long id, CustomerPatchDto dto) {
Customer customer = repository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Cliente não encontrado"));
patchMapper.patch(dto, customer);
validateBusinessRules(customer);
return repository.save(customer);
}
private void validateBusinessRules(Customer customer) {
if (customer.getStatus() == null) {
throw new BusinessException("Status do cliente não pode ficar nulo");
}
}
}
</code>Controller
<code>@RestController
@RequestMapping("/customers")
@RequiredArgsConstructor
public class CustomerController {
private final CustomerAppService service;
@PatchMapping("/{id}")
public ResponseEntity<Customer> patch(@PathVariable Long id, @RequestBody CustomerPatchDto dto) {
Customer updated = service.updatePartially(id, dto);
return ResponseEntity.ok(updated);
}
}
</code>A estrutura acima cobre o caso típico de patch parcial com segurança razoável. Por outro lado, o ganho é claro: o service continua limpo, o mapper concentra o merge e a regra de negócio permanece no lugar certo.
Duas situações reais de produção deixam isso ainda mais concreto. Por outro lado, a primeira é cadastro de cliente com várias telas no front. Ao mesmo tempo, uma tela altera telefone e nome, mas não carrega status nem dados internos. Na prática, se você converter o DTO em uma entidade nova, esses campos somem. Ainda assim, a segunda é atualização de perfil por app mobile em versões diferentes. Por isso, clientes antigos mandam payload incompleto. Além disso, se o backend sobrescreve tudo, usuários de versões antigas quebram dados de campos criados depois.
Erros comuns em APIs reais ao usar mapstruct ignore null spring boot
O erro mais recorrente não está na anotação. Por outro lado, está no desenho do update.
Erro comum: criar uma entidade nova com o mapper
Causa: usar algo como toEntity(dto) e depois chamar save, sem recuperar o registro atual.
Sintoma: campos não enviados são perdidos, relacionamentos podem ser removidos e colunas de auditoria ficam inconsistentes.
Correção: buscar a entidade do banco e aplicar patch com @MappingTarget.
<code>// errado
Customer entity = customerMapper.toEntity(dto);
repository.save(entity);
// certo
Customer entity = repository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Cliente não encontrado"));
customerMapper.updateEntityFromDto(dto, entity);
repository.save(entity);
</code>Erro comum: esperar que null sempre signifique ignorar
Esse ponto é sutil. Por outro lado, em alguns contratos de API, null deveria apagar o valor. Ao mesmo tempo, em outros, deveria ser ignorado. Na prática, mapStruct com IGNORE resolve apenas uma dessas interpretações. Ainda assim, se o seu PATCH precisa distinguir “campo ausente” de “campo presente com null”, o DTO simples já não basta. Por isso, aí entram estratégias mais específicas, como JsonNullable, JsonMergePatch ou wrappers explícitos. Além disso, se você ignorar essa diferença, cria um contrato confuso que o cliente da API nunca entende direito.
Erro comum: aplicar o mesmo mapper em criação e atualização
Criação e atualização parcial têm necessidades diferentes. Por outro lado, em create, null pode ser inválido e deve falhar na validação. Ao mesmo tempo, em update parcial, null pode significar apenas “não quero mexer”. Na prática, reutilizar o mesmo DTO e o mesmo mapper para tudo costuma gerar comportamento torto. Ainda assim, fica pior ainda quando a API mistura PUT com semântica de PATCH.
Erro comum: tentar resolver isso com ControllerAdvice
Existe uma busca comum por “mapstruct spring boot atualizar entidade sem sobrescrever null vs controller advice”. Por outro lado, a comparação faz sentido porque muita gente tenta compensar um update mal implementado com tratamento global de erro. Ao mesmo tempo, só que são problemas diferentes. Na prática, @ControllerAdvice trata exceção e resposta HTTP. Ainda assim, ele não corrige merge de estado da entidade.
Se o backend está zerando campo por receber null, a correção está no fluxo de atualização e no contrato do DTO, não no tratamento global. Por outro lado, para aprofundar essa camada, faz sentido aprofundar em como tratar exceções no spring boot com @controlleradvice e @exceptionhandler.
Quando usar e quando evitar atualizar entidade com MapStruct
Usar MapStruct para update parcial faz bastante sentido quando sua API tem DTOs claros, entidades com muitos campos simples e uma necessidade recorrente de manter a atualização consistente entre endpoints. Por outro lado, também ajuda quando o time quer evitar código repetitivo e prefere mapeamento declarativo revisável em compile time.
Eu usaria sem medo nos seguintes casos: cadastro de cliente, perfil de usuário, dados administrativos, parametrizações e updates de campos diretos sem regra pesada de merge.
Já evitaria jogar tudo no mapper quando existem coleções complexas, objetos aninhados com ciclo de vida próprio ou semântica de null mais elaborada. Por outro lado, exemplo clássico: pedido com lista de itens. Ao mesmo tempo, se o payload traz uma lista parcial, você quer substituir tudo, mesclar por id ou ignorar? Na prática, um mapper automático não adivinha isso. Ainda assim, nesses casos, o service precisa assumir a orquestração e atualizar cada parte com regra explícita.
Outro ponto de atenção é segurança. Por outro lado, em endpoints autenticados, não deixe o DTO aceitar qualquer campo só porque o mapper torna o código mais curto. Ao mesmo tempo, um campo como role, status interno ou limite de crédito não deveria entrar no patch público do usuário. Na prática, nessa discussão de proteção da API, pode ser útil comparar com JWT no Spring Security com Spring Boot: autenticação moderna passo a passo.
Também vale pensar na observabilidade. Por outro lado, se update parcial é sensível para o negócio, monitore falhas, respostas e comportamento anômalo da aplicação. Ao mesmo tempo, como próximo passo operacional, encaixa bem Spring Boot Health Check Actuator Monitoramento sem falhas.
MapStruct vs abordagem improvisada: qual escolha tende a durar mais
Se a comparação for honesta, não existe bala de prata. Por outro lado, existe escolha mais adequada para o tipo de problema.
Quando o update é simples e repetido em muitas partes do sistema, MapStruct com ignore null tende a durar mais porque reduz ruído e padroniza o comportamento. Por outro lado, quando o update tem semântica complexa, patch manual ou até um serviço dedicado de merge fica mais claro.
A escolha pior normalmente não é “manual” ou “MapStruct”. Por outro lado, é a abordagem improvisada: DTO genérico demais, save de entidade nova, mistura de regra de negócio com mapeamento e expectativa de que algum tratamento global esconda o problema. Ao mesmo tempo, isso gera bug silencioso, e bug silencioso em dado de negócio é o tipo mais chato de depurar.
Se você costuma acelerar implementação com ajuda de ferramentas, mas quer evitar código gerado sem critério, uma leitura interessante depois é Ia para programadores java backend exemplo: evite erros.
Mapstruct ignore null spring boot: referencias externas
Para validar detalhes de implementacao e aprofundar a configuracao, vale consultar a documentacao oficial do Spring Security, o guia de claims no JWT.io e a documentacao do Spring Boot.
FAQ
Como ignorar campos null no MapStruct com Spring Boot?
Use um método de update com @MappingTarget e configure @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE). Assim, campos null do DTO não sobrescrevem o valor atual da entidade.
MapStruct funciona bem para PATCH parcial no Spring Boot?
Funciona muito bem para campos simples e DTOs bem definidos. Por outro lado, para coleções, objetos aninhados ou regras em que null pode significar apagar, você provavelmente vai precisar complementar com lógica no service.
Quando usar MapStruct em vez de patch manual na atualização de entidade?
Use MapStruct quando o padrão de atualização parcial se repete e você quer consistência com menos código repetitivo. Por outro lado, prefira patch manual quando a regra de merge é específica demais e precisa ficar explícita no fluxo de negócio.
Conclusão
Se o seu objetivo é atualizar entidade sem sobrescrever null em uma API Spring Boot, o caminho mais estável na maioria dos projetos é carregar a entidade atual, aplicar um mapper com mapstruct ignore null spring boot e manter as regras de negócio no service. Por outro lado, isso resolve a dor real do update parcial sem transformar o código em uma sequência interminável de ifs.
A comparação com patch manual mostra um ponto simples: o manual pode servir no curto prazo, mas o mapper configurado costuma envelhecer melhor quando o sistema cresce. Por outro lado, só não caia na armadilha de achar que IGNORE resolve todos os cenários. Ao mesmo tempo, contrato de API, coleções, null intencional e segurança de campos continuam sendo decisões de design.
Como leitura complementar, faz sentido comparar com Guia completo de Spring Data JPA no Spring Boot sem dor, aprofundar em como tratar exceções no spring boot com @controlleradvice e @exceptionhandler, revisar Spring Boot Health Check Actuator Monitoramento sem falhas e conferir Ia para programadores java backend exemplo: evite erros. Por outro lado, os proximos passos sao validar esse fluxo no seu projeto, ajustar o caso de uso real e cobrir a implementacao com testes.
