All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.mikesafonov.specification.builder.starter.SpecificationBuilder Maven / Gradle / Ivy

There is a newer version: 1.10.0
Show newest version
package com.github.mikesafonov.specification.builder.starter;


import com.github.mikesafonov.specification.builder.starter.annotations.Ignore;
import com.github.mikesafonov.specification.builder.starter.annotations.IsNull;
import com.github.mikesafonov.specification.builder.starter.predicates.PredicateBuilderFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Objects;

/**
 * @author MikeSafonov
 */
@Slf4j
public class SpecificationBuilder {

    private static final String SERIAL_VERSION_UID_NAME = "serialVersionUID";

    private final PredicateBuilderFactory factory = new PredicateBuilderFactory();

    public  Specification buildSpecification(@NonNull F filter) {
        List fields = Utils.getFields(filter);
        log.trace("SB-Filter:  " + filter);
        return (root, query, cb) -> {
            Predicate[] predicates = fields.stream()
                .filter(this::isFieldSupported)
                .map(field -> toPredicate(field, root, cb, query, filter))
                .filter(Objects::nonNull)
                .peek(predicate -> log.trace("SB-Predicate: " + predicate.toString()))
                .toArray(Predicate[]::new);
            return cb.and(predicates);
        };
    }

    private boolean isFieldSupported(@NonNull Field field) {
        return !(field.isAnnotationPresent(Ignore.class) || SERIAL_VERSION_UID_NAME.equals(field.getName()));
    }

    @Nullable
    private  Predicate toPredicate(@NonNull Field field,
                                         @NonNull Root root,
                                         @NonNull CriteriaBuilder cb,
                                         @NonNull CriteriaQuery cq,
                                         @NonNull F filter) {
        Object fieldValue = Utils.getFieldValue(field, filter);
        if (Utils.isNotNullAndNotBlank(fieldValue) || field.isAnnotationPresent(IsNull.class)
            || field.isAnnotationPresent(com.github.mikesafonov.specification.builder.starter.annotations.NonNull.class)) {
            return toPredicate(root, cb, cq, new FieldWithValue(field, fieldValue));
        }
        return null;
    }

    @NonNull
    private  Predicate toPredicate(@NonNull Root root, @NonNull CriteriaBuilder cb,
                                      @NonNull CriteriaQuery cq, @NonNull FieldWithValue field) {
        return factory.createPredicateBuilder(root, cb, cq, field).build();
    }
}