com.github.mikesafonov.specification.builder.starter.ExpressionBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spring-boot-starter-specification-builder Show documentation
Show all versions of spring-boot-starter-specification-builder Show documentation
Spring Boot starter for building specifications in declarative way
package com.github.mikesafonov.specification.builder.starter;
import com.github.mikesafonov.specification.builder.starter.annotations.Join;
import com.github.mikesafonov.specification.builder.starter.annotations.Joins;
import org.springframework.lang.NonNull;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.From;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author MikeSafonov
*/
public class ExpressionBuilder {
private final Map> joinCache = new HashMap<>();
/**
* @param root entity root
* @param field field for expression
* @param restrictions on restrictions
* @param entity type
* @return attribute expression from root or joined attribute expression via {@link Join}
*/
@NonNull
public Expression getExpression(@NonNull Root root, @NonNull FieldWithValue field,
@NonNull Predicate... restrictions) {
return getExpression(root, field.getField(), field.getFieldName(), restrictions);
}
/**
* @param root entity root
* @param field field for expression
* @param restrictions on restrictions
* @param entity type
* @return attribute expression from root or joined attribute expression via {@link Join}
*/
@NonNull
public Expression getExpressionForSubquery(@NonNull Root root, @NonNull FieldWithValue field,
@NonNull Predicate... restrictions) {
return getFrom(root, field.getField(), restrictions).get(field.getFieldName());
}
/**
* @param root entity root
* @param field field for expression
* @param attributeName attribute name
* @param restrictions on restrictions
* @param entity type
* @return attribute expression from root or joined attribute expression via {@link Join}
*/
@NonNull
public Expression getExpression(@NonNull Root root, @NonNull Field field,
@NonNull String attributeName, @NonNull Predicate... restrictions) {
return getCachedFrom(root, field, restrictions).get(attributeName);
}
/**
* @param root entity root
* @param field field for expression
* @param attributeNames array of attributes names
* @param entity type
* @return array of attributes expressions for given attribute names
*/
@NonNull
public Expression[] getExpressions(Root root, FieldWithValue field, String[] attributeNames) {
Expression[] expressions = new Expression[attributeNames.length];
From, ?> from = getCachedFrom(root, field.getField());
for (int i = 0; i < attributeNames.length; i++) {
expressions[i] = from.get(attributeNames[i]);
}
return expressions;
}
/**
* Detects {@link From}. Returns root joined with field if annotation {@link Join} presents and root otherwise.
*
* @param root entity root
* @param field field for expression
* @param restrictions on restrictions
* @param entity type
* @return {@link From} for building expression
*/
private From, ?> getCachedFrom(@NonNull Root root,
@NonNull Field field,
@NonNull Predicate... restrictions) {
if (field.isAnnotationPresent(Join.class) || field.isAnnotationPresent(Joins.class)) {
return getCachedJoin(root, field, restrictions);
}
return root;
}
/**
* Detects {@link From}. Returns root joined with field if annotation {@link Join} presents and root otherwise.
*
* @param root entity root
* @param field field for expression
* @param restrictions on restrictions
* @param entity type
* @return {@link From} for building expression
*/
private From, ?> getFrom(@NonNull Root root,
@NonNull Field field,
@NonNull Predicate... restrictions) {
if (field.isAnnotationPresent(Join.class) || field.isAnnotationPresent(Joins.class)) {
return getJoin(root, field, restrictions);
}
return root;
}
/**
* Get {@link javax.persistence.criteria.Join} from cache or
* creates {@link javax.persistence.criteria.Join} of root with field if absent
*
* @param root entity root
* @param field field for expression
* @param restrictions on restrictions
* @param entity type
* @return root joined with field
*/
@NonNull
private javax.persistence.criteria.Join, ?> getCachedJoin(@NonNull Root root,
@NonNull Field field,
@NonNull Predicate... restrictions) {
Join[] joins = field.getAnnotationsByType(Join.class);
String key = buildKey(joins);
return joinCache.computeIfAbsent(key, s -> buildJoin(joins, root, field, restrictions));
}
/**
* Creates {@link javax.persistence.criteria.Join} of root with field
*
* @param root entity root
* @param field field for expression
* @param restrictions on restrictions
* @param entity type
* @return root joined with field
*/
@NonNull
private javax.persistence.criteria.Join, ?> getJoin(@NonNull Root root,
@NonNull Field field,
@NonNull Predicate... restrictions) {
Join[] joins = field.getAnnotationsByType(Join.class);
return buildJoin(joins, root, field, restrictions);
}
@NonNull
private javax.persistence.criteria.Join, ?> buildJoin(@NonNull Join[] joins,
@NonNull Root root,
@NonNull Field field,
@NonNull Predicate... restrictions) {
javax.persistence.criteria.Join, ?> join = root.join(joins[0].value(), joins[0].type()).on(restrictions);
for (int i = 1; i < joins.length; i++) {
join = join.join(joins[i].value(), joins[i].type());
}
return join;
}
private String buildKey(Join[] joins) {
return Arrays.stream(joins)
.map(join -> join.value() + "(" + join.type() + ")")
.collect(Collectors.joining("."));
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy