4

I'm trying to understand how to use @QuerydslPredicate but my test API fails when it is called:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalStateException: No primary or default constructor found for interface com.querydsl.core.types.Predicate] with root cause

java.lang.NoSuchMethodException: com.querydsl.core.types.Predicate.< init >()

This is the method in my Controller class:

@ResponseBody
@RequestMapping(value = "/user/query", method = RequestMethod.GET)
public Iterable<User> getByCriteria(@QuerydslPredicate(root = User.class) Predicate predicate)
{
    return this.userDao.getByCriteria(predicate);
}

I've used this spring blog post and this example to try and implement my API but I don't understand what I am doing wrong.

Edit #1

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>email-encrypt</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>
    <name>email-encrypt</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <querydsl.version>4.1.4</querydsl.version>
        <springfox.version>2.6.1</springfox.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.59</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcpkix-jdk15on</artifactId>
            <version>1.59</version>
        </dependency>

        <dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcmail-jdk15on</artifactId>
            <version>1.59</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-apt</artifactId>
            <version>${querydsl.version}</version>
        </dependency>

        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-jpa</artifactId>
            <version>${querydsl.version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.derby</groupId>
            <artifactId>derby</artifactId>
            <version>10.14.1.0</version>
            <scope>runtime</scope>
        </dependency>


        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${springfox.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${springfox.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.20</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${build.directory}/generated-sources/java</outputDirectory>
                            <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Edit #2

I've create a sample project here.

D-Dᴙum
  • 7,689
  • 8
  • 58
  • 97

4 Answers4

2

If you comment out the @Configuration on the swagger configuration class it will work. I'm still trying to understand why, I guess that with that annotation the way spring loads the configuration is different and this is causing the issue.

//@Configuration
@EnableSwagger2
public class SwaggerConfiguration extends WebMvcConfigurationSupport
  • I shall try that and let you know the result. Working on something else at the moment. – D-Dᴙum Jul 25 '18 at 18:15
  • I kind of figured it out, querydsl web support has an argument handler that is configured by the @Configuration component that is a WebConfigurer, so you need to make sure that that component is loaded. You can also use componentScan to load QuerydslWebConfiguration.class . Hope that helps – cristobalrosa Jul 26 '18 at 03:07
0

I think your problem lies in your pom.xml. Be sure you are using compatible version of query-dsl. For instance if you use spring-data-jpa 2.0.8, you should use querydsl-* 4.1.4+

<dependency>
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-jpa</artifactId>
    <version>2.0.8.RELEASE</version>
</dependency>

<dependency>
    <groupId>com.querydsl</groupId>
    <artifactId>querydsl-*</artifactId>
    <version>4.1.4</version>
</dependency>

you can check in maven repository which version you need

Edit 1 try to add the querydsl-core to your maven:

 <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-core</artifactId>
        <version>4.1.4</version>
 </dependency>
Stefan Repcek
  • 2,553
  • 4
  • 21
  • 29
  • Thanks for that info. I've checked and I think I'm already using the correct version of querydsl for the spring boot started 2.0.2.RELEASE – D-Dᴙum Jun 17 '18 at 17:47
  • maybe try to add querydsl-core to your pom. Also how you know u using 2.0.2 version? I can't see it in your pom.xml – Stefan Repcek Jun 17 '18 at 17:53
  • It's pulled in via the parent pom configuration and can confirm this by viewing the effective pom. – D-Dᴙum Jun 17 '18 at 19:02
0

Extending on @cristobalrosa's answer, this might be due to web application not being configured by Spring Boot. For instance my project also had a SwaggerConfig extending WebMvcConfigurationSupport:

@Configuration
@EnableSwagger2
public class SwaggerConfig extends WebMvcConfigurationSupport {
    // Docket bean
    
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
    }
}

I removed the inheritance and manual resource handlers, and it works fine now.

Note: In addition to WebMvcConfigurationSupport, things like @EnableWebMvc & WebMvcConfigurer might also lead to Spring Boot's web autoconfiguration not being used.

Sources: Swagger Issue comment

aksh1618
  • 2,245
  • 18
  • 37
0

Same error with me.

I just want to share the situation to may give some hints. So look at my config and dependencies and read articles that I linked. try @EnableWebMvc instead of 'WebMvcConfigurationSupport'

Error

java.lang.IllegalStateException: No primary or default constructor found for interface com.querydsl.core.types.Predicate
Caused by: java.lang.NoSuchMethodException: com.querydsl.core.types.Predicate.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3427)
    at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2631)
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.createAttribute(ModelAttributeMethodProcessor.java:216)

dependencies

    dependencies {
        implementation 'org.springframework.boot:spring-boot-starter-web'
        implementation "org.springframework.data:spring-data-commons"
        implementation "com.querydsl:querydsl-apt:4.3.1"
        implementation "com.querydsl:querydsl-jpa:4.3.1"
    }

Querydsl web support is available in spring-data-commons since 1.11 from https://www.baeldung.com/rest-api-search-querydsl-web-in-spring-data-jpa

Web Mvc Config

In my case, I have to implements WebMvcConfigurer and add @EnableWebMvc instead of WebMvcConfigurationSupport. I don't know why @EnableWebMvc is needed even I had extended WebMvcConfigurationSupport with @Configuration. I just guess WebMvcConfigurationSupport doesn't implements init() of Predicate.

@Configuration
//@EnableSpringDataWebSupport // <-- doesn't necessary for me
@EnableSwagger2
@EnableWebMvc // <-- add
public class SwaggerConfig implements WebMvcConfigurer { //<-- instead of 'WebMvcConfigurationSupport'
   ...
}

QueryDSL web support From Spring document

The feature will be automatically enabled along @EnableSpringDataWebSupport when Querydsl is found on the classpath. https://docs.spring.io/spring-data/jpa/docs/1.9.0.RELEASE/reference/html/#core.web.type-safe

Controller

    @GetMapping
    public List<InputMethodDto.Response> getInputMethodTypeList(
            @QuerydslPredicate(root = InputMethod.class) Predicate predicate) {
        return service.getInputMethodList(predicate);
    }

Repository

public interface InputMethodRepository extends JpaRepository<yourEntity, Long>, QuerydslPredicateExecutor<yourEntity>, QuerydslBinderCustomizer<QyourEntity> {
    @Override
    default void customize(final QuerydslBindings bindings, final QyourEntity root) {
        bindings.bind(String.class).first((StringPath path, String value)-> path.eq(value));
    }
}
hynuah_iia
  • 429
  • 7
  • 14