5

I try to use Query DSL with MongoDB in Spring Boot and I get an error. The app is working successfully without using the library for Query DSL for MongoDB. And I want to use this library because I want to use more complex queries. The code should work, I think there is a little mistake somewhere.

The problem is when I click Maven package I get these errors, unfortunatelly I can't post all the output here:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'hotelController' defined in file [C:\Users\dgs\IdeaProjects\springboot-mongodb\target\classes\com\dgs\springbootmongodb\controller\HotelController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hotelRepository': Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hotelRepository': Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'hotelController' defined in file [C:\Users\dgs\IdeaProjects\springboot-mongodb\target\classes\com\dgs\springbootmongodb\controller\HotelController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hotelRepository': Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hotelRepository': Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!

[ERROR] Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 4.26 s <<< FAILURE! - in com.dgs.springbootmongodb.SpringbootMongodbApplicationTests
[ERROR] contextLoads(com.dgs.springbootmongodb.SpringbootMongodbApplicationTests)  Time elapsed: 0.001 s  <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'hotelController' defined in file [C:\Users\dgs\IdeaProjects\springboot-mongodb\target\classes\com\dgs\springbootmongodb\controller\HotelController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hotelRepository': Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'hotelRepository': Invocation of init method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.mongodb.repository.support.QuerydslMongoPredicateExecutor]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!
Caused by: java.lang.IllegalArgumentException: Did not find a query class com.dgs.springbootmongodb.models.QHotel for domain class com.dgs.springbootmongodb.models.Hotel!
Caused by: java.lang.ClassNotFoundException: com.dgs.springbootmongodb.models.QHotel

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.21.0:test (default-test) on project springboot-mongodb: There are test failures.

It is a hotel booking app and this is the code:

The Hotel model:

package com.dgs.springbootmongodb.models;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.index.IndexDirection;
import org.springframework.data.mongodb.core.index.Indexed;
import org.springframework.data.mongodb.core.mapping.Document;

import java.util.ArrayList;
import java.util.List;

// The Hotel is the aggregate root so this is the entity on which we will apply our annotations

    @Document(collection = "Hotels")
    public class Hotel {

        @Id
        private String id;
        private String name;

        @Indexed(direction = IndexDirection.ASCENDING)
        private int pricePerNight;
        private Address address;
        private List<Review> reviews;

        protected Hotel() {
            this.reviews = new ArrayList<>();
        }

        public Hotel(String name, int pricePerNight, Address address, List<Review> reviews) {
            this.name = name;
            this.pricePerNight = pricePerNight;
            this.address = address;
            this.reviews = reviews;
        }

        public String getId() {
            return id;
        }

        public String getName() {
            return name;
        }

        public int getPricePerNight() {
            return pricePerNight;
        }

        public Address getAddress() {
            return address;
        }

        public List<Review> getReviews() {
            return reviews;
        }
    }

The HotelRepository interface:

package com.dgs.springbootmongodb.dao;

import com.dgs.springbootmongodb.models.Hotel;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.data.mongodb.repository.Query;
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface HotelRepository extends MongoRepository<Hotel, String>, QuerydslPredicateExecutor<Hotel> {

    // findBy + PricePerNight (property name) + LessThan (filter)

    List<Hotel> findByPricePerNightLessThan(int maxPrice);

    @Query(value = "{address.city:?0}")
    List<Hotel> findByCity(String city);
}

The HotelController:

package com.dgs.springbootmongodb.controller;

import com.dgs.springbootmongodb.dao.HotelRepository;
import com.dgs.springbootmongodb.models.Hotel;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/hotels")
public class HotelController {

    private HotelRepository hotelRepository;

    public HotelController(HotelRepository hotelRepository) {
        this.hotelRepository = hotelRepository;
    }

    @GetMapping("/all")
    public List<Hotel> getAllHotels() {

        List<Hotel> hotels = hotelRepository.findAll();

        return hotels;
    }

    @GetMapping("/{id}")
    public Optional<Hotel> getOneHotel(@PathVariable String id) {

        return hotelRepository.findById(id);
    }

    @PostMapping
    public Hotel create(@RequestBody Hotel hotel) {

        return hotelRepository.save(hotel);
    }

    @PutMapping
    public Hotel update(@RequestBody Hotel hotel) {

        return hotelRepository.save(hotel);
    }

    @DeleteMapping("/delete/{id}")
    public List<Hotel> delete(@PathVariable String id) {

        hotelRepository.deleteById(id);

        return hotelRepository.findAll();
    }

    @GetMapping("/price/{maxPrice}")
    public List<Hotel> getByPricePerNight(@PathVariable int maxPrice) {

        List<Hotel> hotels = hotelRepository.findByPricePerNightLessThan(maxPrice);

        return hotels;
    }

    @GetMapping("address/{city}")
    public List<Hotel> getByCity(@PathVariable String city) {

        List<Hotel> hotels = hotelRepository.findByCity(city);

        return hotels;
    }
}

This is the pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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.dgs</groupId>
    <artifactId>springboot-mongodb</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>springboot-mongodb</name>
    <description>Demo project for Spring Boot with Mongo DB</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

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

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

        <!-- Add support for Mongo Query DSL -->

        <dependency>
            <groupId>com.querydsl</groupId>
            <artifactId>querydsl-mongodb</artifactId>
            <version>4.1.3</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mongodb</groupId>
                    <artifactId>mongo-java-driver</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <!-- Add plugin for Mongo Query DSL -->

            <plugin>
                <groupId>com.mysema.maven</groupId>
                <artifactId>apt-maven-plugin</artifactId>
                <version>1.1.3</version>
                <dependencies>
                    <dependency>
                        <groupId>com.querydsl</groupId>
                        <artifactId>querydsl-apt</artifactId>
                        <version>4.1.3</version>
                    </dependency>
                </dependencies>
                <executions>
                    <execution>
                        <phase>generate-sources</phase>
                        <goals>
                            <goal>process</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>target/generated-sources/annotations</outputDirectory>
                            <processor>
                                org.springframework.data.mongodb.repository.support.MongoAnnotationProcessor
                            </processor>
                            <logOnlyOnError>true</logOnlyOnError>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>


</project>

Update

This is the starter class:

@SpringBootApplication
public class SpringbootMongodbApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootMongodbApplication.class, args);
    }
}

This is the structure of the app:

enter image description here enter image description here

elvis
  • 956
  • 9
  • 33
  • 56
  • Can you please share the code of spring starter class, where you have enabled configurations of your project. – Archit Sud Sep 17 '18 at 08:39
  • Hello Archit, I just update the question. Please help me! – elvis Sep 17 '18 at 13:32
  • What is QHotel class? – lethanh Sep 17 '18 at 15:50
  • Mongo Query DSL works like this: exchange your entities and each time it finds classes with that MongoDB annotation it generates other classes for queries, for example in this case we have Hotel which is annotated with @Document so it’s a MongoDB annotation and for this entity it will create a QHotel class to stands for query so for the Hotel class you could automatically generate a query Hotel class and then we can use those auto-generated classes to perform typed queries. – elvis Sep 17 '18 at 15:59
  • Are you sure your QHotel class is generated ? What is the dsl query that you are making ? – s7vr Sep 17 '18 at 16:08
  • Hi Veeram, Yes the QHotel is generated, I just put a photo. I want to use dsl query because I want to filter by multiple criteria, I want to find all the hotels that have a price per night less than a given value but have at least one review with a rating grater than 8. – elvis Sep 17 '18 at 18:39
  • It appears from your screenshot `QHotel` is not at the same package hierarchy as `Hotel`. Spring is looking for com.dgs.springbootmongodb.models.QHotel whereas your QHotel is inside com.dgs.springbootmongodb.QHotel. – s7vr Sep 17 '18 at 19:18
  • @Veeram, and how can I change that? – elvis Sep 18 '18 at 07:06
  • @elvis, the package name seems not to be an issue as it is correctly located as per the error log and screen shot. One small thing that you can try is to add the generated-sources to your classpath in Intellij. (I believe IntelliJ might not be able to find the class event though it is generated because it is not added to the classpath.) You can look here for the help how to add it: https://stackoverflow.com/questions/854264/how-to-add-directory-to-classpath-in-an-application-run-profile-in-intellij-idea – 6harat Sep 18 '18 at 13:38

2 Answers2

4

Remove the target folder and start over.

apt-maven-plugin generates, compiles source and adds to classpath. Adjust the plugin's output directory to target/generated-sources/apt.

Run the maven package phase and verify Q class files are inside models packages in targets/classes location and Q source files are inside models package in target/generated-sources/apt.

s7vr
  • 73,656
  • 11
  • 106
  • 127
  • did you have any success ? I cloned the github project linked in video and followed the above steps and successfully executed the test. Let me know if you have any questions. – s7vr Sep 24 '18 at 15:57
  • The github project linked in video is using Spring Boot version 1.4.2 and I'm using version 2.0.5. I changed the version from 2.0.5 to 1.4.2 and the app works successfully. I think it is a version mismatch that makes this problem. Thank you for your help. – elvis Sep 25 '18 at 09:35
  • Yw.I have only tried with latest spring boot version.1.4.2 version is couple of years old so you should upgrade to latest spring boot version. – s7vr Sep 25 '18 at 11:05
0

I managed to make your code work by doing the following:

Change the outputDirectory to <outputDirectory>target/generated-sources</outputDirectory>

Include @Autowired in HotelController

@Autowired
private HotelRepository hotelRepository;
Eneias Silva
  • 234
  • 1
  • 5