Spring data JPA 如何创建通用规范构建器

Cos*_*aic 7 java generics spring-data-jpa

我有不同的规格类别:

public class UserSpecification implements Specification<ApplicationUser> {
    private SearchCriteria criteria;

    public UserSpecification(SearchCriteria criteria) {
        this.criteria = criteria;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Predicate toPredicate(Root<ApplicationUser> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
       ...
    }
}

public class HotelSpecification implements Specification<Hotel> {

    private SearchCriteria criteria;

    public HotelSpecification(SearchCriteria criteria) {
        this.criteria = criteria;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Predicate toPredicate(Root<Hotel> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
      ...
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,我尝试使用通用构建器来编写相同类型的规范,因为构建器类 99% 是重复的,仅在类类型上有所不同。

public class MySpecificationBuilder {
    private final List<SearchCriteria> params;

    public MySpecificationBuilder () {
        params = new ArrayList<>();
    }

    public MySpecificationBuilder with(String key, String value) {
        params.add(new SearchCriteria(key, value));
        return this;
    }

    public Specification<?> build() {
        if (params.size() == 0) {
            return null;
        }

        List<Specification<?>> specs = new ArrayList<>();
        for (SearchCriteria param : params) {
            specs.add(new UserSpecification(param));  //how to make here generic
        }

        Specification<?> result = specs.get(0);
        for (int i = 1; i < specs.size(); i++) {
            result = Specification.where(result).and(specs.get(i)); //warning 1
        }
        return result;
    }
}
Run Code Online (Sandbox Code Playgroud)

-警告1:在此输入图像描述

我想知道它是否鼓励/是否可以使用通用规范构建器。如果是这样,我如何为不同的规格创建通用构建器?

Jen*_*der 2

如果我正确理解你的目标,这样的事情应该有效。

public <T> Specification<T> build(Function<SearchCriteria, Specification<T>> mappingToSpecification) {
    if (params.size() == 0) {
        return null;
    }

    List<Specification<T>> specs = new ArrayList<>();
    for (SearchCriteria param : params) {
        specs.add(mappingToSpecification.apply(param));  //how to make here generic
    }

    Specification<T> result = specs.get(0);
    for (int i = 1; i < specs.size(); i++) {
        result = Specification.where(result).and(specs.get(i)); //warning 1
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

build方法有一个类型参数,允许您将其用于不同的类型,如下所示:

// Assumes builder.with has been called previously
builder.build(
    searchCriteria -> new MyObjectSpecification((SearchCriteria) searchCriteria)
);
Run Code Online (Sandbox Code Playgroud)