2

I have the below Java 11 method which is invoked by the controller where ID is the required param and status,version are optional params. I had to write multiple repository methods to fetch the record based on those params. Am wondering is there a better/effiecient way to refactor this method with out the if/else ladder?

    @Override
    @Transactional(transactionManager = "customTransactionManager")
    public Optional<String> getInformation(UUID id, Status status, Long version) {
        try {
            Preconditions.checkNotNull(id, ID_MUST_BE_NOT_NULL_MSG);
            if (status != null && version != null) {
                return repository.findByIdAndVersionAndStatus(id, version, status);
            } else if (status != null) {
                return repository.findFirstByIdAndStatus(id, status);
            } else if (version != null) {
                return repository.findFirstByIdAndVersion(id, version);
            } else {
                return repository.findFirstByIdOrderByIdDesc(id);
            }
        } catch (Exception e) {
            log.error(e);
            throw new CustomException(MessageFormat.format(PUBLIC_ERROR_MESSAGE, id));
        }
    }
OTUser
  • 3,788
  • 19
  • 69
  • 127
  • Does this answer your question? [Spring Data optional parameter in query method](https://stackoverflow.com/questions/32728843/spring-data-optional-parameter-in-query-method) – Jens Schauder Sep 17 '21 at 07:49

2 Answers2

3

You could use Specifications for that:

private Specification<YourEntity> toSpecification(UUID id, Status status, Long version) {
    return (root, query, builder) -> {
        Set<Predicate> predicates = new HashSet<>();
        predicates.add(builder.equal(root.get("id"), id));
        if (status != null) predicates.add(builder.equal(root.get("status"), status));
        if (version != null) predicates.add(builder.equal(root.get("version"), version));
        return builder.and(predicates.toArray(Predicate[]::new));
    };
}

If you let your repository extend JpaSpecificationExecutor you can use the build specification object like so:

Specification<YourEntity> specification = toSpecification(id, status, version);
Optional<YourEntity> result = repository.findOne(specification);

When using Hibernate Metamodel Generator you can also write builder.equal(YourEntity_.id, id) instead of builder.equal(root.get("id"), id).

slauth
  • 2,667
  • 1
  • 10
  • 18
0

In addition to the accepted answer, I find Query By Examples much more intuitive and simple.

https://www.baeldung.com/spring-data-query-by-example would be a good start.

It basically creates a query based on non-null fields from your jpa entity.