Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

Executando método dentro do orElse() primeiro.

Bom dia pessoal, Estou com o seguinte problema: Tenho um regra no meu sistema que não permite criar pessoas com mesmo documento e o mesmo nome. Então eu faço essa verificação com o SpringJpa retornando um Optional e orElse() e se não existir eu crio uma nova pessoa.

private Person savePerson(String document, String name) {

        Person person = new Person();
        person.setDocument(document);
        person.setName(name);
        person.setId(UUID.randomUUID());
        return personRepository.save(person);
    }

Porém antes de criar a pessoa eu uso este método para verificar se ela existe ou não...

public Person checkPersonOrCreate(Person person) {
        return personRepository.findByDocumentAndName(person.getDocument(), person.getName()).
                .orElse(savePerson(person.getDocument(),  person.getName()));
    }

O problema é que, quanto executo o método checkPersonOrCreate e a pessoa existi, o que é executado primeiro é a chama para o método savePerson, salvando a pessoa na base e duplicando as informações. O que é errado seguindo a regra do meu sistema. Consegui resolver esta situação retirando o orElse() e usando o isPresent() , porém não consegui entender por que o meu método savePerson dentro do orElse() é executado mesmo o meu método findByDocumentAndName() retornando uma pessoa que existe.

Código que funciona

public Person checkPersonOrCreate(Person person) {
        return (personRepository.findByDocumentAndName(person.getDocument(), person.getName()).isPresent())
                ? personRepository.findByDocumentAndName(person.getDocument(), person.getName()).get()
                : savePerson(person.getDocument(), person.getName());
    }
2 respostas
solução!

Olá Andrade, tudo bem?

O que ocorre é que o método orElse() sempre vai executar o resultado da função que for passada pra ele. A questão é que o orElse() costuma ser mais adequado quando queremos retornar um objeto que já foi construído. Senão caímos nesse caso de execuções duplicadas que você comentou.

exemplo mais simples:

Optional.ofNullable(stringQuePodeSerNula).orElse("");

Então o que poderíamos fazer aqui é usar o orElseGet(). Esse método recebe uma função como parâmetro (para ser executada apenas se o optional for empty).

exemplo:

findByName(name)
.orElseGet(() -> savePerson(name))

Então concluindo, o que você pode fazer é usar o orElseGet() ao invés do orElse().

Muito boa a explicação, fiz a alteração e funcionou. Obrigado.