'What is the return type of Specification after creating a join with criteria API

I don't understand how to return the query after making the join and adding the predicate in the specification in this code. Can Anyone help me?

public class QueriesEntity {    
    @Column(name = "query_id")
    @Id
    private int queryId;
    
    private String name;
    
    private String description;
    
    private String query;
    
    private Integer owner;
    
    @Column(name = "conn_id")
    private Integer dataSourceId;
    
    @Column(name = "created_dt")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDt;
    
    @Column(name = "updated_dt")
    @Temporal(TemporalType.TIMESTAMP)
    private Date updatedDt; 
    
    @Column(name = "container_id")
    private Integer containerId;
    
    @OneToOne
    @JoinColumn(name = "conn_id", updatable = false, insertable = false)
    private DataSourceEntity dataSourceEntity;

public static Specification filters(Integer containerId, Integer queryID, Integer datasourceId) {

    return new Specification<QueriesEntity>() {
        private static final long serialVersionUID = 1L;
        
        @Override
        public Predicate toPredicate(Root<QueriesEntity> root, CriteriaQuery<?> query,
                CriteriaBuilder criteriaBuilder) {
            
             query = criteriaBuilder.createQuery(QueriesEntity.class);
             root = query.from(QueriesEntity.class);
            Join<QueriesEntity, DataSourceEntity> join = root.join("dataSourceEntity", JoinType.INNER);
            
            List<Predicate> outerPreds = new ArrayList<>();
            if (containerId != null) {
                Predicate containerIdPred = criteriaBuilder.equal(root.get("containerId"), containerId);
                outerPreds.add(containerIdPred);
            }
            if(queryID > 0) {
                Predicate queryIdPred = criteriaBuilder.equal(root.get("queryId"), queryID);
                outerPreds.add(queryIdPred);
            }
            if(datasourceId != null) {
                Predicate datasourceIdPred = criteriaBuilder.equal(root.get("dataSourceId"), datasourceId);
                outerPreds.add(datasourceIdPred);
            }
            return criteriaBuilder.and(outerPreds.toArray(new Predicate[outerPreds.size()]));
        }
    };
}


Solution 1:[1]

When using the Join option you shouldn't use the root to get fields, use the Join instead:

if (containerId != null) {
    Predicate containerIdPred = criteriaBuilder.equal(join.get("containerId"), containerId);
    outerPreds.add(containerIdPred);
}

Example code:

public static Specification<QueriesEntity> filters(Integer containerId, Integer queryID, Integer datasourceId) {
    return (root, query, cb) -> {
        Join<QueriesEntity, DataSourceEntity> join = root.join("dataSourceEntity", JoinType.INNER);
        List<Predicate> outerPreds = new ArrayList<>();
        if (containerId != null) {
            Predicate containerIdPred = cb.equal(join.get("containerId"), containerId);
            outerPreds.add(containerIdPred);
        }
        if(queryID > 0) {
            Predicate queryIdPred = cb.equal(join.get("queryId"), queryID);
            outerPreds.add(queryIdPred);
        }
        if(datasourceId != null) {
            Predicate datasourceIdPred = cb.equal(root.get("dataSourceId"), datasourceId);
            outerPreds.add(datasourceIdPred);
        }
        return cb.and(outerPreds.stream().toArray(Predicate[]::new));
    };
}

Sources

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

Source: Stack Overflow

Solution Source
Solution 1