woemler
woemler

Reputation: 7169

Creating multiple aliases for the same QueryDSL path in Spring Data

I have a generic Spring Data repository interface that extends QuerydslBinderCustomizer, allowing me to customize the query execution. I am trying to extend the basic equality testing built into the default repository implementation, so that I can perform other query operations using Spring Data REST. For example:

GET /api/persons?name=Joe%20Smith  // This works by default
GET /api/persons?nameEndsWith=Smith  // This requires custom parameter binding.

The problem I am having is that every alias of an entity path I create seems to override the preceding alias bindings.

@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable>
    extends PagingAndSortingRepository<T, ID>, QueryDslPredicateExecutor<T>, QuerydslBinderCustomizer { 

    @Override
    @SuppressWarnings("unchecked")
    default void customize(QuerydslBindings bindings, EntityPath entityPath){

        Class<T> model = entityPath.getType();
        Path<T> root = entityPath.getRoot();
        for (Field field: model.getDeclaredFields()){
            if (field.isSynthetic()) continue;
            Class<?> fieldType = field.getType();
            if (fieldType.isAssignableFrom(String.class)){
                // This binding works by itself, but not after the next one is added
                bindings.bind(Expressions.stringPath(root, field.getName()))
                        .as(field.getName()  + "EndsWith")
                        .first((path, value) -> {
                            return path.endsWith(value);
                        });
                // This binding overrides the previous one
                bindings.bind(Expressions.stringPath(root, field.getName()))
                        .as(field.getName()  + "StartsWith")
                        .first((path, value) -> {
                            return path.startsWith(value);
                        });
            }
        }
    }
}

Is it possible to create more than one alias for the same field? Can this be accomplished in a generic way?

Upvotes: 44

Views: 3560

Answers (1)

apetrelli
apetrelli

Reputation: 718

You can create a transient property bound to QueryDSL this way:

@Transient
@QueryType(PropertyType.SIMPLE)
public String getNameEndsWith() {
    // Whatever code, even return null
}

If you are using the QueryDSL annotation processor, you will see the "nameEndsWith" in the metadata Qxxx class, so you can bind it like any persisted property, but without persisting it.

Upvotes: 1

Related Questions