Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QuerydslBindings not working with inheritance [DATACMNS-941] #1396

Closed
spring-projects-issues opened this issue Nov 22, 2016 · 5 comments
Closed
Assignees
Labels
type: enhancement
Milestone

Comments

@spring-projects-issues
Copy link

@spring-projects-issues spring-projects-issues commented Nov 22, 2016

Casey Link opened DATACMNS-941 and commented

First, I'm not sure if this is a bug or a feature request.

The issue is that QueryDslBindings doesn't seem to work with inherited types. I want to filter a base type by the properties on the sub type. It is best explained with some code.

note: in most of the code examples I've omitted things to make it readable and only included the pertinent bits.

I have a base entity like so:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING)
class Person {
  @Id
  Long id;
}

And a few children types, here are two:

@Entity
@DiscriminatorValue("employee")
class Employee extends Person {

  @Column
  String name;
}
@Entity
@DiscriminatorValue("teenager")
class Teenager extends Person {

  @Column
  String name;
}

(ignore the fact that name should be on Person if this was a real data model)

Then I have the main object I want to query by later on: PersonContainer

/**
 * Holds persons!
 */
@Entity
class PersonContainer {
  @OneToOne
  private Person person;
}
@RepositoryRestResource(collectionResourceRel = "person-container", path = "person-containers")
interface PersonContainerRepository extends CrudRepository<PersonContainer, Long>,
        QuerydslBinderCustomizer<QPersonContainer>
{

    default void customize(QuerydslBindings bindings, QPersonContainer personContainer)
    {
        bindings.bind(personContainer.person.as(QEmployee.class).name)
                .first((path, value) -> path.containsIgnoreCase(value));

        bindings.bind(personContainer.person.as(QTeenager.class).name)
                .first((path, value) -> path.containsIgnoreCase(value));
    }
}

Everything is ready! Now I'm ready to make my api request:

example.com/person-containers?person.name=Andy

In the end the stacktrace I get is

java.lang.NullPointerException: null
	at org.springframework.util.ReflectionUtils.getField(ReflectionUtils.java:143)
	at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.reifyPath(QuerydslPredicateBuilder.java:190)
	at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.reifyPath(QuerydslPredicateBuilder.java:193)
	at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.getPath(QuerydslPredicateBuilder.java:168)
	at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.invokeBinding(QuerydslPredicateBuilder.java:137)
	at org.springframework.data.querydsl.binding.QuerydslPredicateBuilder.getPredicate(QuerydslPredicateBuilder.java:116)
	at org.springframework.data.rest.webmvc.config.QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver.postProcess(QuerydslAwareRootResourceInformationHandlerMethodArgumentResolver.java:91)
	at org.springframework.data.rest.webmvc.config.RootResourceInformationHandlerMethodArgumentResolver.resolveArgument(RootResourceInformationHandlerMethodArgumentResolver.java:92)
	at org.springframework.data.rest.webmvc.config.RootResourceInformationHandlerMethodArgumentResolver.resolveArgument(RootResourceInformationHandlerMethodArgumentResolver.java:40)

So, here we are.

  1. Is this type of querying supported by spring data?
  2. Am I just doing it incorrectly or is this a bug?

If this is not a bug or feature request and instead a user error, I'm happy to move this to SO (but I suspect that this is actual a feature request)


Affects: 1.12.5 (Hopper SR5)

Backported to: 1.13 RC1 (Ingalls)

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Nov 22, 2016

Oliver Drotbohm commented

Thanks for the detailed writeup Casey. Currently, that's not supported (which you made obvious), as there seem to be some smarts missing in the predicate builder to work with the casts. We should be able to get that fixed

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Nov 23, 2016

Casey Link commented

Thanks for the quick reply Oliver. Looking forward to a future release with this feature.

In the meantime though, is there a way to get the full querydsl binding support for query parameters for 99% of the queries and then provide a custom parser/predicate for more advanced queries?

I'm imagining a rest data controller method or custom repository method that has as arguments the querydslbindings plus some extra specific parameters that could be manually added as a predicate. Does that make sense?

The goal is to be able to use query params to filter across all common and complex types using spring-data without having to specify all the query param options manually

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Nov 23, 2016

Oliver Drotbohm commented

I haven't tested that but you might be able to exclude the paths that you want to get this working on and then add those bindings to the resulting predicate manually in a controller method that takes the values provided via request parameters

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Nov 23, 2016

Casey Link commented

Super Oliver thanks. I managed to get this working, with some song-and-dance, as described over here.

Edit: to clarify I didn't get the exclusions working for the path "person.name" like:

bindings.excluding(personContainer.person.as(QEmployee.class).name);

I always got an NPE like that in the main body of this issue. Instead I just chose to use a query param name that didn't clash with a property path on my entity.

Not ideal of course, because once this issue is fixed, clients will have to be updated to use the actual property path, but at least its a stop gap.

If my QueryDSL foo was better, I could probably create a StringPath manually and exclude that

@spring-projects-issues
Copy link
Author

@spring-projects-issues spring-projects-issues commented Dec 12, 2016

Oliver Drotbohm commented

This should be in place

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement
Projects
None yet
Development

No branches or pull requests

2 participants