2

Let's say I have a generated Entity like this:

public class QCandidate extends EntityPathBase<Candidate> {

public final com.avisto.candisearch.persistance.model.enums.QAvailabilityEnum availability;

public final DatePath<java.util.Date> birthDate = createDate("birthDate", java.util.Date.class);

public final NumberPath<Long> cvId= createNumber("cvId", Long.class);

public final StringPath city = createString("city");

}

My input values are the fields names ("availability","birthDate","cvId"...) and a string value that I should use to perform a 'like' with all the fields.

I want to build a query starting from the field names that:

  • casts Dates and Numbers to strings and lowercases them
  • if the field is an EntityPathBase (like availability) extracts the id and then again casts to lowercased string

Something like:

lower(cast(C.cvId as varchar(255))) like 'value'

for each field.

I can do this usign querydsl-sql module, but I want to achieve it using only the jpa module.

I'm not interested in the mechanism of creating the FULL 'where' clause (I know I have to use the BooleanBuilder, or at least, this is what I do in the sql version).

What I want to know is how to create the individual 'where' conditions basing on the field type.

I'm trying to use a PathBuilder but it seems that to use methods like "getString or getBoolean" you already have to know the type of the field that you are trying to extract. In my case, since I start just from the field name, I can't use these methods and I don't know how to identify the type of each field starting from the field name, so I'm stuck.

1 Answer 1

2
+100

May be a bit ugly, but workable suggestion.

Note, that the number of field types that PathBuilder accepts is quite limited.

You definitely can find the field class from field name (using reflection or by maintaining a member map updated with each field).

Just implement handling for each specific type.

This can be ugly bunch of if..else or, for more elegant solution, create Map of type handlers [class->handler], each handler implements interface method to handle specific type.

Pseudocode:

//building query
for each field
  Class fieldClass = findFieldClas(.., field) //use reflection or map
  PathHandler handler = handlers.get(fieldClass)
  handler.process( ...)

//type handler interface
public interface Handler{
  public xx process(? extends DataPathBase);
}

//specific type handler implementation
public class BooleanHandler implements Handler{
  public xx process(? extends DataPathBase path){
    BooleanPath bPath = (BooleanPath)path;
    ...
}

//intitialize handlers map singleton or a factory in advance    
handlers.put(BooleanPath.class, new BooleanHandler());
...

Note this is a generic solution if you have many classes. If you have only one specific class, you can just create a permanent map of fieldName->Handler and avoid lookup for the field class.

Again, this is by no means a pretty solution, but should work.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for answering, but I'd like to avoid "hardcoding" any kind of mapping. I feel I should be able to do what I want without that... :/
I would not call it quite "hardcoded". Set of DatePathBase is quite limited and will change very rarely with library upgrade, if at all. Also, if you don't use new types after upgrade in the processed fields, you don't need to update anything, basically it is one time work. You are not mapping field names to handlers, you are mapping field types, so it is more like a kind of "framework" than hardcoded handling, a thin abstraction layer to API.
you are right, introspection is absolutely the right way to go. silly me for not thinking to it :) Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.