I'm trying to create a generic method for filter in depth using Criteria API.
For example if I want to filter an attribute "id.person.name" or more than 3 nested attributes.
I already have the filter for 2 nested attributes working, like: "person.name".
The elseif condition below is working with 3 nested attributes, but I'm trying to create a method that I won't need to change if a new case appears.
private <T> List<Predicate> filterInDepth(Map<String, String> params, Root<T> root,
CriteriaBuilder criteriaBuilder, String field, Class<T> clazz)
throws NoSuchFieldException {
List<Predicate> predicates = new ArrayList<>();
String[] compositeFields = field.split(REGEX_FIELD_SPLITTER);
if (compositeFields.length == 2) {
Join<Object, Object> join = root.join(compositeFields[0]);
predicates.add(criteriaBuilder.equal(join.get(compositeFields[1]),
params.get(field)));
}
else if (clazz.getDeclaredField(compositeFields[0]).getType()
.getDeclaredField(compositeFields[1]).getType()
.getDeclaredField(compositeFields[2]) != null) {
predicates.add(criteriaBuilder.equal(root.get(compositeFields[0])
.get(compositeFields[1]).get(compositeFields[2]), params.get(field)));
}
return predicates;
}
So I'm trying to split the String, loop and create an expression. But I couldn't concat Expressions.
I found a solution I hope help someone.
private <T> List<Predicate> filterInDepth(Map<String, String> params, Root<T> root,
CriteriaBuilder criteriaBuilder, String field, Class<T> clazz)
throws NoSuchFieldException {
List<Predicate> predicates = new ArrayList<>();
String[] compositeFields = field.split(REGEX_FIELD_SPLITTER);
if (isNestedFieldExists(clazz, compositeFields)) {
Path path = null;
for (String part : compositeFields) {
if (path == null) {
path = root.get(part);
}
else {
path = path.get(part);
}
}
predicates.add(criteriaBuilder.equal(path, params.get(field)));
}
return predicates;
}
private boolean isNestedFieldExists(Class clazz, String[] fieldChain)
throws NoSuchFieldException {
for (String field : fieldChain) {
Field f = clazz.getDeclaredField(field);
if (f.getType() == null) {
return false;
}
clazz = f.getType();
}
return true;
}