Search code examples
spring-bootgradlespring-data-mongodbquerydsl

NoSuchMethodException QueryDSL with Spring Boot & Spring Data Mongo


I am trying to implement Query DSL on my Spring Boot 2.0.4.RELEASE app that uses Spring Data Mongo 2.0.4.RELEASE & Gradle 4.10. I am using Spring Tool Suite for running it locally.

Did the following steps which I found from multiple sources including Spring data documentation:

  • created gradle/querydsl.gradle which has below content to generate Q classes
    apply plugin: "com.ewerk.gradle.plugins.querydsl"

    sourceSets {
        main {
            java {
                srcDir "$buildDir/generated/source/apt/main"
            }
        }
    }

    querydsl {
        springDataMongo = true
        querydslSourcesDir = "$buildDir/generated/source/apt/main"
    }

    dependencies {
        compile "com.querydsl:querydsl-mongodb:4.1.4"
        compileOnly "com.querydsl:querydsl-apt:4.1.4"
    }

    sourceSets.main.java.srcDirs = ['src/main/java']

  • Calling above gradle file from main build.gradle as shown below
    buildscript {

        ext { springBootVersion = "2.0.4.RELEASE" }

        repositories { mavenCentral() }

        dependencies {
            classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
            classpath "gradle.plugin.com.ewerk.gradle.plugins:querydsl-plugin:1.0.9"
        }
    }

    plugins {
        id "java"
        id "eclipse"
        id "org.springframework.boot" version "2.0.4.RELEASE"
        id "io.spring.dependency-management" version "1.0.6.RELEASE"
    }

    sourceCompatibility = 1.8

    repositories { mavenCentral() }

    dependencies {
        ...
        compile("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
        compile("org.springframework.boot:spring-boot-starter-data-mongodb:${springBootVersion}")
        ...
    }

    apply from: 'gradle/querydsl.gradle'

    /* Added this because Eclipse was not able to find generated classes */
    sourceSets.main.java.srcDirs = ['build/generated/source/apt/main','src/main/java']

    compileJava.dependsOn processResources
    processResources.dependsOn cleanResources

  • After this updated the Repository annotated interface as below. Note: I also use Fragment Repository FragmentOrderRepository for some custom queries.
    public interface OrderRepository<D extends OrderDAO>
            extends EntityRepository<D>, PagingAndSortingRepository<D, String>, FragmentOrderRepository<D>, QuerydslPredicateExecutor<D> {}

  • Then in controller created a GET mapping as shown here

    @RestController
    public class OrderController {
        @GetMapping(value="/orders/dsl", produces = { "application/json" })
        public ResponseEntity<List> getOrdersDSL(@QuerydslPredicate(root = OrderDAO.class) Predicate predicate, Pageable pageable, @RequestParam final MultiValueMap<String, String> parameters) {
            return (ResponseEntity<List>) orderService.getTools().getRepository().findAll(predicate, pageable);
        }
    }

  • Then in my runner class I added EnableSpringDataWebSupport annotation
    @SpringBootApplication
    @EnableSpringDataWebSupport
    public class SampleApp {
        public static void main(String[] args) {
            SpringApplication.run(SampleApp.class, args);
        }
    }

With this my app starts up without any errors but when I try hitting the path http://localhost:5057/orders/dsl?email=test@test.com

I get a NoSuchMethodException with message No primary or default constructor found for interface com.querydsl.core.types.Predicate.

Can anyone please help with some pointers to solve this issue?

It seems that parameters are not getting resolved to a type.

---- UPDATE 09/19/19 ----

While debugging I found that a class HandlerMethodArgumentResolverComposite which finds ArgumentResolver for given MethodParameter from a List of argumentResolvers(of type HandlerMethodArgumentResolver). This list does not contain QuerydslPredicateArgumentResolver. Hence it is not able to resolve the arguments.

This means QuerydslWebConfiguration which adds above resolver for Predicate type is not getting called, which in turn indicates that some AutoConfiguration is not happening.

Probably I am missing some annotation here.


Solution

  • Found the mistake I was doing, was missing EnableWebMvc annotation on my Configuration annotated class. Details are in this documentation.