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

com.introproventures.graphql.jpa.query.schema.impl.JpaPredicateBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2017 IntroPro Ventures Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.introproventures.graphql.jpa.query.schema.impl;

import com.introproventures.graphql.jpa.query.schema.impl.PredicateFilter.Criteria;
import graphql.language.NullValue;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.From;
import jakarta.persistence.criteria.Path;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.PluralAttribute;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

/**
 * Supported types to build predicates for
 *
 * 
    *
  • Boolean
  • *
  • Byte
  • *
  • Short
  • *
  • Character
  • *
  • Integer
  • *
  • Long
  • *
  • Float
  • *
  • Double
  • *
  • java.math.BigInteger
  • *
  • java.math.BigDecimal
  • *
  • java.lang.String
  • *
  • java.util.Date
  • *
  • java.time.LocalDate
  • *
  • java.time.LocalDateTime *
  • java.time.OffsetDateTime *
  • java.time.ZonedDateTime *
  • java.time.Instant
  • *
  • java.time.LocalTime
  • *
  • java.util.Calendar
  • *
  • java.sql.Date
  • *
  • java.sql.Time
  • *
  • java.sql.Timestamp
  • *
  • java.util.UUID
  • *
* */ class JpaPredicateBuilder { public static final Map, Class> WRAPPERS_TO_PRIMITIVES = new HashMap, Class>(); public static final Map, Class> PRIMITIVES_TO_WRAPPERS = new HashMap, Class>(); public static final Set> JAVA_SCALARS = new LinkedHashSet<>(); static { PRIMITIVES_TO_WRAPPERS.put(boolean.class, Boolean.class); PRIMITIVES_TO_WRAPPERS.put(byte.class, Byte.class); PRIMITIVES_TO_WRAPPERS.put(char.class, Character.class); PRIMITIVES_TO_WRAPPERS.put(double.class, Double.class); PRIMITIVES_TO_WRAPPERS.put(float.class, Float.class); PRIMITIVES_TO_WRAPPERS.put(int.class, Integer.class); PRIMITIVES_TO_WRAPPERS.put(long.class, Long.class); PRIMITIVES_TO_WRAPPERS.put(short.class, Short.class); PRIMITIVES_TO_WRAPPERS.put(void.class, Void.class); WRAPPERS_TO_PRIMITIVES.put(Boolean.class, boolean.class); WRAPPERS_TO_PRIMITIVES.put(Byte.class, byte.class); WRAPPERS_TO_PRIMITIVES.put(Character.class, char.class); WRAPPERS_TO_PRIMITIVES.put(Double.class, double.class); WRAPPERS_TO_PRIMITIVES.put(Float.class, float.class); WRAPPERS_TO_PRIMITIVES.put(Integer.class, int.class); WRAPPERS_TO_PRIMITIVES.put(Long.class, long.class); WRAPPERS_TO_PRIMITIVES.put(Short.class, short.class); WRAPPERS_TO_PRIMITIVES.put(Void.class, void.class); JAVA_SCALARS.addAll( Arrays.asList( Boolean.class, Byte.class, Character.class, Double.class, Float.class, Integer.class, Long.class, Short.class, BigInteger.class, BigDecimal.class, String.class, Date.class, LocalDate.class, LocalDateTime.class, ZonedDateTime.class, Instant.class, LocalTime.class, Calendar.class, OffsetDateTime.class, java.sql.Date.class, java.sql.Time.class, java.sql.Timestamp.class, UUID.class ) ); } private final CriteriaBuilder cb; /** * JpaPredicateBuilder constructor * * @param cb */ public JpaPredicateBuilder(CriteriaBuilder cb) { this.cb = cb; } protected Predicate addOrNull(Path root, Predicate p) { Predicate pr = cb.isNull(root); return cb.or(p, pr); } /** * * @param root * @param filter * @return */ protected Predicate getStringPredicate(Path root, PredicateFilter filter) { // list or arrays only for in and not in, between and not between Predicate arrayValuePredicate = mayBeArrayValuePredicate(root, filter); if (arrayValuePredicate == null) { String compareValue = filter.getValue().toString(); Expression fieldValue = root; if ( filter.anyMatch( Criteria.EQ_, Criteria.NE_, Criteria.LIKE_, Criteria.STARTS_, Criteria.ENDS_, Criteria.LOWER ) ) { compareValue = compareValue.toLowerCase(); fieldValue = cb.lower(fieldValue); } if (filter.getCriterias().contains(Criteria.IN)) { CriteriaBuilder.In in = cb.in(fieldValue); return in.value(compareValue); } if (filter.getCriterias().contains(Criteria.NIN)) { return cb.not(fieldValue.in(compareValue)); } if (filter.anyMatch(Criteria.EQ, Criteria.LOWER, Criteria.EQ_)) { return cb.equal(fieldValue, compareValue); } else if (filter.anyMatch(Criteria.NE, Criteria.NE_)) { return cb.notEqual(fieldValue, compareValue); } else if (filter.anyMatch(Criteria.LIKE, Criteria.LIKE_)) { compareValue = "%" + compareValue + "%"; } else if (filter.anyMatch(Criteria.STARTS, Criteria.STARTS_)) { compareValue = compareValue + "%"; } else if (filter.anyMatch(Criteria.ENDS, Criteria.ENDS_)) { compareValue = "%" + compareValue; } else if (filter.anyMatch(Criteria.EXACT, Criteria.CASE)) { // do nothing } // default empty else { compareValue = "%"; } return cb.like(fieldValue, compareValue); } return arrayValuePredicate; } protected Predicate getBooleanPredicate(Path root, PredicateFilter filter) { Boolean bool = (Boolean) filter.getValue(); if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { bool = !bool; } return cb.equal(root, bool); } /** * Do not confuse with Java type Integer, it is for all types without * fractional component: BigInteger, Long, Integer, Short, Byte * * @param root * @param filter * @return */ protected Predicate getIntegerPredicate(Path root, PredicateFilter filter) { // list or arrays only for in and not in Predicate arrayValuePredicate = mayBeArrayValuePredicate(root, filter); if (arrayValuePredicate == null && filter.getValue() != null && filter.getValue() instanceof Number) { if (filter.getCriterias().contains(PredicateFilter.Criteria.IN)) { CriteriaBuilder.In in = cb.in(root); return in.value(filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NIN)) { return cb.not(root.in(filter.getValue())); } if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lt(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.gt(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.LE)) { return cb.le(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.ge(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } return cb.equal(root, filter.getValue()); } return arrayValuePredicate; } protected Predicate mayBeArrayValuePredicate(Path path, PredicateFilter filter) { // arrays only for in if (filter.getValue().getClass().isArray()) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && !filter.getCriterias().contains(PredicateFilter.Criteria.NIN) ) { CriteriaBuilder.In in = cb.in(path); for (Object n : (Object[]) filter.getValue()) { in.value(n); } return in; } else if ( filter.getCriterias().contains(PredicateFilter.Criteria.NE) || filter.getCriterias().contains(PredicateFilter.Criteria.NIN) ) { return cb.not(path.in((Object[]) filter.getValue())); } else if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values = (Object[]) filter.getValue(); if (values.length == 2) { Expression name = path.get(filter.getField()); Predicate between = cb.between( name, cb.literal((String) values[0]), cb.literal((String) values[1]) ); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } else if ((filter.getValue() instanceof Collection)) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && !filter.getCriterias().contains(PredicateFilter.Criteria.NIN) && !( filter.getCriterias().contains(Criteria.NOT_BETWEEN) || filter.getCriterias().contains(Criteria.BETWEEN) ) ) { CriteriaBuilder.In in = cb.in(path); for (Object n : (Collection) filter.getValue()) { in.value(n); } return in; } else if ( filter.getCriterias().contains(PredicateFilter.Criteria.NE) || filter.getCriterias().contains(PredicateFilter.Criteria.NIN) ) { return cb.not(path.in((Collection) filter.getValue())); } else if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.NOT_BETWEEN) || filter.getCriterias().contains(Criteria.BETWEEN) ) ) { Expression name = (Expression) path; Collection collection = (Collection) filter.getValue(); if (collection.size() == 2) { Object[] values = collection.toArray(); Expression fromValue = cb.literal(values[0]); Expression toValue = cb.literal(values[1]); Predicate between = cb.between(name, fromValue, toValue); if (filter.getCriterias().contains(Criteria.BETWEEN)) { return between; } return cb.not(between); } } } return null; } protected Predicate getFloatingPointPredicate(Path root, PredicateFilter filter) { Predicate arrayValuePredicate = mayBeArrayValuePredicate(root, filter); if (arrayValuePredicate == null && filter.getValue() != null && filter.getValue() instanceof Number) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lt(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.gt(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.ge(root, (Number) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.le(root, (Number) filter.getValue()); } return arrayValuePredicate; } protected Predicate getDatePredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof Date) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (Date) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (Date) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (Date) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (Date) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromDate = cb.literal((Date) values[0]); Expression toDate = cb.literal((Date) values[1]); Predicate between = cb.between(name, fromDate, toDate); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } protected Predicate getLocalDatePredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof LocalDate) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (LocalDate) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (LocalDate) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (LocalDate) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (LocalDate) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromDate = cb.literal((LocalDate) values[0]); Expression toDate = cb.literal((LocalDate) values[1]); Predicate between = cb.between(name, fromDate, toDate); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } protected Predicate getLocalDateTimePredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof LocalDateTime) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (LocalDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (LocalDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (LocalDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (LocalDateTime) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromDateTime = cb.literal((LocalDateTime) values[0]); Expression toDateTime = cb.literal((LocalDateTime) values[1]); Predicate between = cb.between(name, fromDateTime, toDateTime); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } protected Predicate getInstantPredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof Instant) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (Instant) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (Instant) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (Instant) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (Instant) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromDate = cb.literal((Instant) values[0]); Expression toDate = cb.literal((Instant) values[1]); Predicate between = cb.between(name, fromDate, toDate); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } protected Predicate getLocalTimePredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof LocalTime) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (LocalTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (LocalTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (LocalTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (LocalTime) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromTime = cb.literal((LocalTime) values[0]); Expression toTime = cb.literal((LocalTime) values[1]); Predicate between = cb.between(name, fromTime, toTime); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } protected Predicate getZonedDateTimePredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof ZonedDateTime) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (ZonedDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (ZonedDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (ZonedDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (ZonedDateTime) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromDateTime = cb.literal((ZonedDateTime) values[0]); Expression toDateTime = cb.literal((ZonedDateTime) values[1]); Predicate between = cb.between(name, fromDateTime, toDateTime); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } protected Predicate getOffsetDateTimePredicate(Path root, PredicateFilter filter) { if (filter.getValue() != null && filter.getValue() instanceof OffsetDateTime) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LT)) { return cb.lessThan(root, (OffsetDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GT)) { return cb.greaterThan(root, (OffsetDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.GE)) { return cb.greaterThanOrEqualTo(root, (OffsetDateTime) filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(root, filter.getValue()); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(root, filter.getValue()); } // LE or default return cb.lessThanOrEqualTo(root, (OffsetDateTime) filter.getValue()); } else if (filter.getValue().getClass().isArray() || filter.getValue() instanceof Collection) { if ( !filter.getCriterias().contains(PredicateFilter.Criteria.NE) && ( filter.getCriterias().contains(Criteria.BETWEEN) || filter.getCriterias().contains(Criteria.NOT_BETWEEN) ) ) { Object[] values; if (filter.getValue().getClass().isArray()) { values = (Object[]) filter.getValue(); } else { values = ((Collection) filter.getValue()).toArray(); } if (values.length == 2) { Expression name = (Expression) root; Expression fromDateTime = cb.literal((OffsetDateTime) values[0]); Expression toDateTime = cb.literal((OffsetDateTime) values[1]); Predicate between = cb.between(name, fromDateTime, toDateTime); if (filter.getCriterias().contains(Criteria.BETWEEN)) return between; return cb.not(between); } } } return null; } private Predicate getUuidPredicate(Path field, PredicateFilter filter) { if (filter.getValue() == null) { return null; } final Predicate arrayPredicate = mayBeArrayValuePredicate(field, filter); if (arrayPredicate != null) { return arrayPredicate; } final UUID compareValue = (UUID) filter.getValue(); if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(field, compareValue); } if (filter.getCriterias().contains(PredicateFilter.Criteria.IN)) { final CriteriaBuilder.In in = cb.in(field); return in.value(compareValue); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(field, compareValue); } return null; } private Predicate getEnumPredicate(Path field, PredicateFilter filter) { if (filter.getValue() == null) { return null; } final Predicate arrayPredicate = mayBeArrayValuePredicate(field, filter); if (arrayPredicate != null) { return arrayPredicate; } final Enum compareValue = (Enum) filter.getValue(); if (filter.getCriterias().contains(PredicateFilter.Criteria.EQ)) { return cb.equal(field, compareValue); } if (filter.getCriterias().contains(PredicateFilter.Criteria.IN)) { final CriteriaBuilder.In in = cb.in(field); return in.value(compareValue); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NIN)) { final CriteriaBuilder.In in = cb.in(field); return cb.not(in.value(compareValue)); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.notEqual(field, compareValue); } return null; } @SuppressWarnings("unchecked") private Predicate getTypedPredicate(From from, Path field, PredicateFilter filter) { Class type = filter.getJavaType(); Object value = filter.getValue(); Set criterias = filter.getCriterias(); Attribute attribute = filter.getAttribute(); if (value == null) { return cb.disjunction(); } if (criterias.contains(Criteria.IS_NULL)) { return (boolean) value ? cb.isNull(field) : cb.isNotNull(field); } else if (criterias.contains(Criteria.NOT_NULL)) { return (boolean) value ? cb.isNotNull(field) : cb.isNull(field); } if (type.isPrimitive()) type = PRIMITIVES_TO_WRAPPERS.get(type); if (NullValue.class.isInstance(value) && JAVA_SCALARS.contains(type)) { if (criterias.contains(Criteria.EQ)) { return cb.isNull(field); } else if (criterias.contains(Criteria.NE)) { return cb.isNotNull(field); } } if (type.equals(String.class)) { return getStringPredicate((Path) field, filter); } else if ( type.equals(Long.class) || type.equals(BigInteger.class) || type.equals(Integer.class) || type.equals(Short.class) || type.equals(Byte.class) ) { return getIntegerPredicate((Path) field, filter); } else if (type.equals(BigDecimal.class) || type.equals(Double.class) || type.equals(Float.class)) { return getFloatingPointPredicate((Path) field, filter); } else if (java.util.Date.class.isAssignableFrom(type)) { return getDatePredicate((Path) field, filter); } else if (type.equals(java.time.LocalDate.class)) { return getLocalDatePredicate((Path) field, filter); } else if (type.equals(LocalDateTime.class)) { return getLocalDateTimePredicate((Path) field, filter); } else if (type.equals(Instant.class)) { return getInstantPredicate((Path) field, filter); } else if (type.equals(LocalTime.class)) { return getLocalTimePredicate((Path) field, filter); } else if (type.equals(ZonedDateTime.class)) { return getZonedDateTimePredicate((Path) field, filter); } else if (type.equals(OffsetDateTime.class)) { return getOffsetDateTimePredicate((Path) field, filter); } else if (type.equals(Boolean.class)) { return getBooleanPredicate(field, filter); } else if (type.equals(UUID.class)) { return getUuidPredicate((Path) field, filter); } else if (Collection.class.isAssignableFrom(type)) { // collection join for plural attributes if (PluralAttribute.class.isInstance(attribute) || EntityType.class.isInstance(attribute)) { Expression> expression = from.get(filter.getField()); Predicate predicate; if (Collection.class.isInstance(filter.getValue())) { List restrictions = new ArrayList<>(); Collection.class.cast(filter.getValue()).forEach(v -> restrictions.add(cb.isMember(v, expression))); predicate = cb.and(restrictions.toArray(new Predicate[] {})); } else { predicate = cb.isMember(filter.getValue(), expression); } if (filter.anyMatch(Criteria.NIN, Criteria.NE)) { return cb.not(predicate); } return predicate; } } else if (type.isEnum()) { return getEnumPredicate((Path>) field, filter); } // TODO need better detection mechanism else if (Object.class.isAssignableFrom(type)) { if (filter.getCriterias().contains(PredicateFilter.Criteria.LOCATE)) { return cb.gt(cb.locate(from.get(filter.getField()), value.toString()), 0); } else { Object object = value; if (Collection.class.isInstance(value)) { object = getValues(object, type); } else { object = getValue(object, type); } if ( filter.getCriterias().contains(PredicateFilter.Criteria.EQ) || filter.getCriterias().contains(PredicateFilter.Criteria.NE) ) { Predicate equal = cb.equal(from.get(filter.getField()), object); if (filter.getCriterias().contains(PredicateFilter.Criteria.NE)) { return cb.not(equal); } return equal; } else if ( filter.getCriterias().contains(PredicateFilter.Criteria.IN) || filter.getCriterias().contains(PredicateFilter.Criteria.NIN) ) { CriteriaBuilder.In in = cb.in(from.get(filter.getField())); if (Collection.class.isInstance(object)) { Collection.class.cast(object).forEach(in::value); } else { in.value(object); } if (filter.getCriterias().contains(PredicateFilter.Criteria.NIN)) { return cb.not(in); } return in; } } } throw new IllegalArgumentException("Unsupported field type " + type + " for field " + filter.getField()); } private Object getValue(Object object, Class type) { try { Constructor constructor = type.getConstructor(Object.class); if (constructor != null) { Object arg = NullValue.class.isInstance(object) ? null : object; return constructor.newInstance(arg); } } catch (Exception ignored) {} return object; } private Object getValues(Object object, Class type) { Collection objects = new ArrayList<>(); for (Object value : Collection.class.cast(object).toArray()) { objects.add(getValue(value, type)); } return objects; } /** * Makes predicate for field of primitive type * * @throws IllegalArgumentException if field type is not primitive or * unsupported * @param field * @param filter * @return constructed predicate, returns null if value cannot be converted * to field type */ public Predicate getPredicate(From from, Path field, PredicateFilter filter) { return getTypedPredicate(from, field, filter); } }