Lets say that i have an abstract class Product and i have two more entities that extend it ProductA and ProductB with different fields. I am using Product repository to search for all of them using Specification and SpecificationBuilder using some common fields. What i want to accomplish is to detect what type of product it is (A or B) and based on that to use different search query.
For example ProductA has stock and ProductB has featured so naturally if i insert search criteria quantity and try to do a specification on Product repo, i would like the api to search for ProductA. Is this form of search possible in any way? This is my current code:
public interface ProductRepo extends JpaRepository<Product, Integer>,JpaSpecificationExecutor<Product>{
}
public class ProductSpecificationBuilder {
public final ProductSpecificationBuilder with(final String orPredicate, final String key
, final String operation, Object value, final String prefix, final String suffix) {
System.out.println("called "+value);
//Fixing boolean value
if (!key.equals("visible") || key.equals("modified")) {
System.out.println("not equal visible");
SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0));
if (op != null) {
if (op == SearchOperation.EQUALITY) { // the operation may be complex operation
final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX);
final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX);
System.out.println("prefix "+startWithAsterisk+" "+endWithAsterisk);
if (startWithAsterisk && endWithAsterisk) {
op = SearchOperation.CONTAINS;
} else if (startWithAsterisk) {
op = SearchOperation.ENDS_WITH;
} else if (endWithAsterisk) {
op = SearchOperation.STARTS_WITH;
}
}else if (op == SearchOperation.LIKE) {
System.out.println("we got like in builder");
}
params.add(new SearchCriteria(orPredicate, key, op, value));
}
}
return this;
}
}
public class ProductSpecification implements Specification<Product>{
@Override
public Predicate toPredicate(final Root<Product> root, final CriteriaQuery<?> query, final CriteriaBuilder builder) {
//TODO JOIN class for nested search for promotion
switch (criteria.getOperation()) {
case EQUALITY:
return builder.equal(root.get(criteria.getKey()), criteria.getValue());
case NEGATION:
return builder.notEqual(root.get(criteria.getKey()), criteria.getValue());
case GREATER_THAN:
return builder.greaterThan(root.get(criteria.getKey()), criteria.getValue().toString());
case LESS_THAN:
return builder.lessThan(root.get(criteria.getKey()), criteria.getValue().toString());
case LIKE:
return builder.like(root.get(criteria.getKey()), criteria.getValue().toString());
case STARTS_WITH:
return builder.like(root.get(criteria.getKey()), criteria.getValue() + "%");
case ENDS_WITH:
return builder.like(root.get(criteria.getKey()), "%" + criteria.getValue());
case CONTAINS:
return builder.like(root.get(criteria.getKey()), "%" + criteria.getValue() + "%");
default:
return null;
}
}
}
public enum SearchOperation {
EQUALITY, NEGATION, GREATER_THAN, LESS_THAN, LIKE, STARTS_WITH, ENDS_WITH, CONTAINS;
public static final String[] SIMPLE_OPERATION_SET = { ":", "!", ">", "<", "~","@"};
public static final String OR_PREDICATE_FLAG = "'";
public static final String ZERO_OR_MORE_REGEX = "*";
public static final String OR_OPERATOR = "OR";
public static final String AND_OPERATOR = "AND";
public static final String LEFT_PARANTHESIS = "(";
public static final String RIGHT_PARANTHESIS = ")";
public static SearchOperation getSimpleOperation(final char input) {
switch (input) {
case ':':
return EQUALITY;
case '!':
return NEGATION;
case '>':
return GREATER_THAN;
case '<':
return LESS_THAN;
case '~':
return LIKE;
case '@':{
return CONTAINS;
}
default:
return null;
}
}
}
And my Product classes
@Entity
@Table(name = "products")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
@Column(name = "id")
private int id;
-----Common fields----
}
public class ProductA extends Product{ int stock; }
public class ProductB extends Product{ int featured; }
If you have any questions feel free to ask. Any form of help would be much appreciated! Thank you in advance.