javajpacriteriahibernate-criteriapredicate

IllegalStateException using CriteriaBuilder for getting a List in Java


Summarizing, I Have 3 entities, the main one is the entity named "Rac". It contains a List of "RacNatureza", which contain a attribute "Natureza".

Rac

    @Entity
    @Table(name = "rac")
    public class Rac {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long idRac;    

    @OneToMany(mappedBy = "rac", cascade = {CascadeType.ALL}, orphanRemoval = true)
    @JsonManagedReference //para evitar recursão infinita do JSON
    private List<RacNatureza> racNaturezas;

    //...getters and setters ok
}

RacNatureza

@Entity
@Table(name = "rac_natureza")
public class RacNatureza implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_rac_natureza")
    private Long idRacNatureza;

    @ManyToOne
    @JsonBackReference //coloquei para evitar a recursao infinita de JSON
    @JoinColumn(name="id_rac")
    private Rac rac;

    @ManyToOne
    @JoinColumn(name="id_natureza")
    private Natureza natureza;

    @Column(name = "principal")
    private Boolean principal;
}

Natureza

@Entity
@Table(name = "natureza")
public class Natureza {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id_natureza")
    private Integer idNatureza;
    private String descricao;

    @OneToMany(mappedBy = "natureza", fetch = FetchType.EAGER, orphanRemoval = true)
    @JsonIgnore
    private List<RacNatureza> racNatureza;
}

I'm trying to develop a search using filters, in this case, the user select a list of "Natureza" and then, the system have to show what "Rac" contain the Natureza which was selected by the user. For that, I've tried to implement using Entitymanager and Criteriabuilder.

I've tried to write the expression like this but isn't working (I'm not using metamodel):

@PersistenceContext
private EntityManager entityManager;

@Override
public List<Rac> filtrar(RacFilter racFilter) {
    CriteriaBuilder builder = entityManager.getCriteriaBuilder();
    CriteriaQuery<Rac> criteria = builder.createQuery(Rac.class);
    Root<Rac> root = criteria.from(Rac.class);

    Predicate[] predicates = criarRestricoes(racFilter, builder, root);
    criteria.where(predicates);

    TypedQuery<Rac> query = entityManager.createQuery(criteria);
    return query.getResultList();

}

@Override
public Predicate[] criarRestricoes(RacFilter racFilter, CriteriaBuilder builder, Root<Rac> root) {
    List<Predicate> predicates = new ArrayList<>();
    if (racFilter.getNaturezas() != null) {
        predicates.add(
                builder.equal(root.<List<RacNatureza>>get("racNaturezas").<Natureza>get("natureza"), racFilter.getNaturezas()) );
    }   
    return predicates.toArray(new Predicate[predicates.size()]);
}

So, using this code above I've received the following error: Caused by: java.lang.IllegalStateException: Illegal attempt to dereference path source [null.racNaturezas] of basic type

I believe that the error is in this line, but I really don't know how to fix it:

    predicates.add(
            builder.equal(root.<List<RacNatureza>>get("racNaturezas").<Natureza>get("natureza"), racFilter.getNaturezas()) );
}   

Solution

  • Replace root.get("racNaturezas") with root.join("racNaturezas")

    Please don't ask me why we can't use get