7

I have several entities and use Spring Data JPA repositories with specifications query my database. Therefore I created a generic class SpecBuilder to build my queries based on a query description (MyQueryDescriptor).

public class Specs { public static <T extends MyEntityIFace> Specification<T> myfind(final MyQueryDescriptor qDesc) { return new Specification<T>() { @Override public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) { try { return SpecBuilder.mySpec(root, criteriaQuery, criteriaBuilder, qDesc); } catch (Exception e) { ...handle error... } } }; } } 

My repositories:

public interface Entity1DAO extends Repository<Entity1,Long>, JpaSpecificationExecutor { } 

and

public interface Entity2DAO extends Repository<Entity2,Long>, JpaSpecificationExecutor { } 

Now there are 3 things I am not quite sure about:
1)
Is this use of a generic SpecBuilder a clean design?

2)
Is there a way to avoid writing those repository interfaces for each entity? Let's say a generic repository?

3)
The MyQueryDescriptor class has a method to return an instance of an Entity, which will be queried.
What would be a clean way to obtain the according repository based on the entity class, avoiding a switch case? I was thinking about putting an annotation with the specific repository class to each entity but it feels a bit smelly.
Should I create a factory and inject a map like

Entity1.class => Entity1DAO Entity2.class => Entity2DAO 

?

2
  • 1
    The "problem" that I see is separate entities probably aren't similar enough for a generic repo. You could get basic ones I guess; like findAll(), save(T), etc but why not let the details be left to inference? You can let the system generate nice things like findThisByThatAndTheOther(T that, T2 theOther);? Commented Oct 1, 2015 at 6:50
  • I know that a single repo would cost me the flexibility to use inference for search methods like findThisByThatAndTheOther(T that, T2 theOther) but my SpecBuilder class should be able to create all criteria queries I'd need. Therefore creating empty repositories for many entities feels like a lot of overhead. Commented Oct 1, 2015 at 7:03

2 Answers 2

2

You can use entity inheritance and use Spring Expression Language (SpEL) to make repository issue calls on right entities. Like in my last update here

Sign up to request clarification or add additional context in comments.

1 Comment

How exactly does this help with JpaSpecificationExecutor?
0

Is this use of a generic SpecBuilder a clean design?

Depends what criteria you have for clean design. Will the same MyQueryDescriptor work for different entities? Surely they have different properties, so you need to ask yourself whether a given MyQueryDescriptor could be mistakenly used for an incompatible entity and ways in which you could prevent it. We cannot comment on that since we don't know how your SpecBuilder works.

Is there a way to avoid writing those repository interfaces for each entity? Let's say a > generic repository?

Nope. It's not much boilerplate either, though.

  1. The MyQueryDescriptor class has a method to return an instance of an Entity, which will be queried. What would be a clean way to obtain the according repository based on the entity class, avoiding a switch case?

I suppose you could use getBeanProvider at runtime, where you would define resolvableType as CrudRepository<MyEntityType, IdType>.

However, if I were you, I'd consider switching to using JPA Criteria API without the JpaSpecificationExecutor abstraction on top of it. That would probably prove to be more natural. The design of Spring repositories is centered around the idea of the repository organizing queries around the given specific entity, whereas your use case seems to go in exactly the opposite direction - to dynamically pick an entity and then find a repository to fit in, just to satisfy Spring's restrictions. You seem to be fighting the framework in that regard.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.