Fala Thiago, tudo bem ?
Fica difícil ver qual a causa do NullPointer só olhando o código aqui. Você poderia verificar se tem referencia pro dao ou pro produto como o matheus comentou.
Mas independente disso você poderia tentar algo assim:
form:
<form:form action="${ s:mvcUrl('PC#gravar').build() }" method="post" commandName="produto" >
<div>
<label>Código Original</label>
<form:input path="codOriginal"/>
<form:errors path="codOriginal" />
</div>
...
controller:
@Autowired
private ProdutoDao produtoDao;
...
@InitBinder
public void initBinder(WebDataBinder binder) {
binder.addValidators(new ProdutoValidator(produtoDao));
}
@RequestMapping(method = RequestMethod.POST)
public ModelAndView gravar(@Valid Produto produto, BindingResult result, RedirectAttributes redirectAttributes) {
if (result.hasErrors()) {
return pform(produto);
}
...
dao.salva(produto);
return "redirect:/produtos";
}
validator:
public class ProdutoValidator implements Validator {
private ProdutoDao produtDao;
public ProdutoValidator(ProdutoDao produtoDao) {
this.produtoDao = produtoDao;
}
@Override
public void validate(Object target, Errors errors) {
Produto produto = (Produto) target;
if (dao.buscaPorId(produto.getCodigo()) != null) {
errors.rejectValue("codigo", "codigo.existente", "Já existe um produto cadastrado com esse codigo");
}
}
// aqui a gente só diz pro Spring se ele pode aplicar ou não esse validator para o alvo validado. No caso, somente será aplicado se o alvo for um produto
@Override
public boolean supports(Class clazz) {
return Produto.class.isAssignableFrom(clazz);
}
}
dao:
public Produto buscaPorId(Integer id) {
// retorna a entidade encontrada ou nulo se nao existir esse id
return entityManager.find(Produto.class, id);
}
Explicando:
Você pode criar um Validator pra produto aproveitando o Spring Validator (implements Validator). O Spring então vai aplicar a validação durante o processo de binding (assim como ele aplica as validações da Bean Validation - @NotNull nas propriedades de produto, por exemplo). Independente de qual erro de validação for aplicado ele adiciona os problemas no mesmo objeto Errors verificado no binding result.
A implementação fica bem simples. Você poderia apenas chamar um findById e se vier algo diferente de nulo significa que ja tem registro salvo com aquele codigo. Então poderia adicionar um erro de validação ao processo de bind errors.rejectValue("codigo", "codigo.existente", "Já existe produto cadastrado com esse código")
, onde a primeira String é o atributo com erro, a segunda é uma chave se quiser chavear mensagens de validação, e a terceira seria a própria mensagem padrão pra esse erro de validação.
Você não precisa necessariamente usar o Validator do Spring, mas em geral o fluxo e a lógica pra esse tipo de validação é a mesma.
@RequestMapping(method = RequestMethod.POST)
public ModelAndView gravar(@Valid Produto produto, BindingResult result, RedirectAttributes redirectAttributes) {
SeuValidator seuValidator = new SeuValidator(dao);
if (!seuValidator.valida(produto)) {
result.rejectValue("codigo", "codigo.existente");
}
// ou voce poderia passar a referencia do BindingResult pro validator pra nao deixar esse codigo aqui no controller. etc
if (result.hasErrors()) {
return pform(produto);
}
...
dao.salva(produto);
return "redirect:/produtos";
}
Espero ter ajudado. Abraço!