Your example is unfortunately not very understandable to me. In my humble opinion that query can and should be simplified.
None the less there is a way to get jsonb_extract_path (and other jsonb functions) into a JPA predicate (using hibernate as an implementation).
Let's say u want to retrieve from your z table the record(s) where bar.foo exists.
The sql for it would look like this:
select * from z where jsonb_extract_path(bar, 'foo') is not null;
To get this query into a JPA predicate you will need to write an own predicate that extends
org.hibernate.query.criteria.internal.predicate.AbstractSimplePredicate
and implements
org.hibernate.query.criteria.internal.expression.BinaryOperatorExpression
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
import org.hibernate.query.criteria.internal.ParameterRegistry;
import org.hibernate.query.criteria.internal.Renderable;
import org.hibernate.query.criteria.internal.compile.RenderingContext;
import org.hibernate.query.criteria.internal.expression.BinaryOperatorExpression;
import org.hibernate.query.criteria.internal.expression.LiteralExpression;
import org.hibernate.query.criteria.internal.predicate.AbstractSimplePredicate;
import javax.persistence.criteria.Expression;
import java.io.Serializable;
import static java.lang.String.format;
public class ExtractJsonPath extends AbstractSimplePredicate implements
BinaryOperatorExpression<Boolean>, Serializable {
private final Expression<?> leftHandSide;
private final Expression<?> rightHandSide;
public ExtractJsonPath(CriteriaBuilderImpl criteriaBuilder, Expression<?> leftHandSide, Expression<?> rightHandSide) {
super(criteriaBuilder);
this.leftHandSide = leftHandSide;
this.rightHandSide = rightHandSide;
}
@Override
public Expression getLeftHandOperand() {
return leftHandSide;
}
@Override
public Expression getRightHandOperand() {
return rightHandSide;
}
@Override
public void registerParameters(ParameterRegistry registry) {
Helper.possibleParameter(getLeftHandOperand(), registry);
Helper.possibleParameter(getRightHandOperand(), registry);
}
@Override
public String render(boolean isNegated, RenderingContext renderingContext) {
return format(
" jsonb_extract_path(%s, %s) ",
((Renderable) getLeftHandOperand()).render(renderingContext),
((Renderable) getRightHandOperand()).render(renderingContext)
);
}
}
Somewhere in your code you will need to put a where-clause in a query:
query.where(builder.isNotNull(
new ExtractJsonPath(
(CriteriaBuilderImpl) builder,
root.get("bar"),
builder.literal("foo")
));
And so u could use that function in a JPA predicate.
Note that you can deep nest that construct.. If you need to check that bar.foo.x exists, you'd write:
new ExtractJsonPath(
(CriteriaBuilderImpl) builder,
new ExtractJsonPath(
(CriteriaBuilderImpl) builder,
root.get("bar"),
builder.literal("foo")
),
builder.literal("x")
));
Simpler in sql, since you could just write:
select * from z where jsonb_extract_path(bar, 'foo', 'x') is not null;
At this point i would like to apologize for not fully adopting your example.
I hope this is an acceptable suggestion (or at least a descent start) and wish you a lot of success.