'Generalize Specifications with joins

I'm using Spring Specifications to filter and sort through a class using multiple joins.

For example, I have the class ContextData

public class ContextData implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @Id
    private String uuid;
    
    @ManyToOne
    @JoinColumn(name = "purpose_code", insertable = false, updatable = false)
    private ClPurpose clPurpose;
    
    @Column(name = "purpose_code")
    private String clPurposeCode;
        
    //many other fields to filter
    ...
}

the class ClPurpose

public class ClPurpose implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    private String code;

    @OneToMany(mappedBy="clPurpose")
    private List<ContextData> contextData;

    @OneToMany(mappedBy = "clPurpose")
    private List<ClPurposeTranslation> clPurposeTranslations;
    ...
}

the class ClPurposeTranslation

public class ClPurposeTranslation implements Serializable {

    @EmbeddedId
    private TranslationPK id;

    private String name;

    @ManyToOne
    @JoinColumn(name = "code", insertable = false, updatable = false)
    private ClPurpose clPurpose;
    ...
}

and the class TraslationPK

@Embeddable
public class TranslationPK implements Serializable {

    @Column(name = "code")
    private String code;

    @Enumerated(EnumType.STRING)
    private LangIsoCode langIsoCode;
    ...
}

So I want to filter through ContextData by the ClPurposeTranslation.name in a specific langIsoCode. Currently I'm doing something like that

public class SearchCriteria {
    private String key;

    private SearchOperation operation;

    private Object value;
    ...
}

and

public class ContextDataSpecification {
    SearchCriteria criteria;
    
    LangIsoCode langIsoCode;


    @Override
    public Predicate toPredicate(@NonNull Root<ContextData> root, @NonNull CriteriaQuery<?> query, @NonNull CriteriaBuilder builder) {
        switch (criteria.getOperation()) {
            case EQUALITY:
                if ("clPurposeCode".equals(criteria.getKey())) {
                    Join<ContextData, ClPurposeTranslation> purposeJoin = root.join("clPurpose").join("clPurposeTranslations");
                    Join<Join<ContextData, ClPurposeTranslation>, TranslationPK> translationJoin = purposeJoin.join("id");

                    return equalAndEqualLanguagePredicate(builder, purposeJoin.get("name"), translationJoin.get("langIsoCode"));
                }
                
                //checking against many other fields...
        }
    }
}

Keep in mind, that i want to do this for 20+ fields in 2-3 others classes. Is there a way to generalize this process and avoid using if statements to check against the field i want to filter?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source