#Size testing does not throw DataIntegrityViolationException - java

I am trying to test the #Size annotation on the following class, I expect the test to throw an Exception when a Topic with name lenght less than 3 is "saved" using the repository. The problem is that nothing is thrown.
Class:
#Entity
#Builder
#Data
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "topic")
public class TopicEntity implements Serializable {
#Id #GeneratedValue( strategy = GenerationType.IDENTITY )
private Long id;
#Column( length=200, unique = true, nullable = false )
#Size(min = 3, max = 200, message
= "Topic name must be between 3 and 200 characters")
#NotBlank
private String name;
#Builder.Default
#OneToMany( mappedBy="theTopic", cascade = CascadeType.MERGE )
List<QuestionEntity> questions = new ArrayList<>();
#Builder.Default
#OneToMany( mappedBy="theTopic", cascade = CascadeType.MERGE )
List<Source> sources = new ArrayList<>();
}
Test, it is actually in a Test Class file, per request of one of you guys I am including the full class code.. Looks like the #Size annotation has nothing to do with the Database Constraints, please let me know of some good practices for applying/testing this kind of Validations
#DataJpaTest
public class TopicRepositoryTest {
#Autowired
TopicRepository repository;
TopicEntity topicA, topicB;
#BeforeEach
public void setUp(){
topicA = TopicEntity.builder()
.name("Java")
.build();
topicB = TopicEntity.builder()
.name("Java")
.build();
}
#Test
void giventopicsWithSameName_whenSaveThem_thenThrowException(){
repository.save(topicA);
assertThrows(DataIntegrityViolationException.class,
() -> repository.save(topicB));
}
#Test
void givenNullTopicName_whenSaveTopic_thenThrowException(){
TopicEntity topic = TopicEntity.builder()
.build();
assertThrows(DataIntegrityViolationException.class,
() -> repository.save(topic));
}
#Test
void givenShortTopicName_whenSaveTopic_thenThrowException(){
TopicEntity topic = TopicEntity.builder()
.name("")
.build();
assertThrows(DataIntegrityViolationException.class,
() -> repository.save(topic));
}
}
Repository:
package com.learning.javainterviewquestions.repositories;
import org.springframework.data.jpa.repository.JpaRepository;
import com.learning.javainterviewquestions.entities.TopicEntity;
public interface TopicRepository extends JpaRepository < TopicEntity, Long >{
TopicEntity findByName(String topic);
}
POM:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.0.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.learning</groupId>
<artifactId>java-interview-questions</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>java-interview-questions</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.12.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

When using #DataJpaTest, every test is executed within a transaction (-> JavaDoc for the annotation includes the #Transactional annotation). This means, that your data is never actually flushed to the DB unless you use the .saveAndFlush method or flush the changes diretly with the EntityManager. You have to options:
1. Use .saveAndFlush
or
2. Use #SpringBootTest instead of #DataJpaTest

Related

Error on getting records by id using r2dbc

In sandbox project trying reactive webflux with springboot and postgres. I added r2dbc, created endpoints - get all records and post endpoints work, but appeared problem with requests which use path variable (get one record, or delete by id)
Here is my code:
#SpringBootApplication
#EnableR2dbcAuditing
public class Springboot2Application {
public static void main(String[] args) {
SpringApplication.run(Springboot2Application.class, args);
}
}
Controller:
#RequiredArgsConstructor
#RestController
#RequestMapping("/api/v1")
public class ToDoController {
private final ToDoRepository repository;
#GetMapping(value = "/to-do/{toDoId}", produces = {
MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE, MediaType.TEXT_XML_VALUE})
public Mono<ResponseEntity<ToDo>> getToDo(#Valid #PathVariable Long toDoId) {
return repository.findById(toDoId)
.map(ResponseEntity::ok);
}
}
repository:
#Repository
public interface ToDoRepository extends R2dbcRepository<ToDo,Long> {
}
entity:
#Data
#RequiredArgsConstructor
#Table(name = "to_do")
public class ToDo {
#Id
private Long id;
#Version
private Long version;
#NotNull
#NotBlank
private String description;
#CreatedDate
private Timestamp created;
#LastModifiedDate
private Timestamp modified;
private boolean completed;
}
r2dbc config:
#Configuration
#EnableR2dbcRepositories(basePackages = "com.springboot2.repository")
public class R2DBCConfig extends AbstractR2dbcConfiguration {
#Bean
public ConnectionFactory connectionFactory() {
return ConnectionFactories.get(
ConnectionFactoryOptions.builder()
.option(DRIVER, "postgresql")
.option(HOST, "localhost")
.option(PORT, 5432)
.option(USER, "admin")
.option(PASSWORD, "admin")
.option(DATABASE, "springdb")
.build());
}
#Bean
ReactiveTransactionManager transactionManager(ConnectionFactory connectionFactory) {
return new R2dbcTransactionManager(connectionFactory);
}
}
And my pom file:
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.springboot</groupId>
<artifactId>springboot</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot2</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>8</java.version>
<spring-cloud.version>2021.0.3</spring-cloud.version>
</properties>
<dependencies>
<!-- DB,ORM, and plugins-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
<version>0.8.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Reactive libs-->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
table creation sql:
CREATE TABLE to_do
(
ID SERIAL primary key ,
version bigint,
description char(255),
created timestamp,
modified timestamp,
completed boolean
);
So when I execute GET http://localhost:8080/api/v1/to-do/3 I get:
java.lang.IllegalStateException: Required identifier property not found for class com.springboot2.domain.ToDo
I tried to define this using #Query in repository, but got same result. I suppose problem can be either in my table, or in entity, but I can't see it. And also seems #Version does not work(every time writes null to table)
The problem may be in wrong import of #Id annotation in your domain.
It should be from package
org.springframework.data.annotation.Id
But in your case it is from package
javax.persistence
Also, consider the naming of fields. As in your domain id is declared as "id", I can see in your create script id as "ID" (in uppercase).

Spring Java - Parameter 0 of constructor

I'm trying to write a simple CRUD program and I get this error. The program is based after codecademy project. Not sure why I doesn't work.
If I comment out the constructor the error disappears.I don't have anything in my properties.
Can someone give me a hand?
Description:
Parameter 0 of constructor in com.example.FitApp3.controller.FoodController required a bean of type 'com.example.FitApp3.repository.FoodRepository' that could not be found.
Action:
Consider defining a bean of type 'com.example.FitApp3.repository.FoodRepository' in your configuration.
Process finished with exit code 1
This is my code:
Entity/Food.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Food extends com.example.FitApp3.model.Entity {
private String foodName;
private int foodKcal;
private int foodProtein;
private int foodCarb;
private int foodFat;
public String getFoodName() {
return foodName;
}
public void setFoodName(String foodName) {
this.foodName = foodName;
}
public int getFoodKcal() {
return foodKcal;
}
public void setFoodKcal(int foodKcal) {
this.foodKcal = foodKcal;
}
public int getFoodProtein() {
return foodProtein;
}
public void setFoodProtein(int foodProtein) {
this.foodProtein = foodProtein;
}
public int getFoodCarb() {
return foodCarb;
}
public void setFoodCarb(int foodCarb) {
this.foodCarb = foodCarb;
}
public int getFoodFat() {
return foodFat;
}
public void setFoodFat(int foodFat) {
this.foodFat = foodFat;
}
}
Repository/FoodRepository.java
public interface FoodRepository extends CrudRepository<Food, Integer> {}
Controller/FoodController.java
#RestController
public class FoodController {
private FoodRepository foodRepository;
public FoodController(FoodRepository foodRepository) {
this.foodRepository = foodRepository;
}
}
Mainclass
#SpringBootApplication
public class FitApp3Application {
public static void main(String[] args) {
SpringApplication.run(FitApp3Application.class, args);
System.out.println("hello world");
}
}
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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>FitApp3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>FitApp3</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.5.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Can you add #Repository annotation to FoodRepository interface.
#Repository
public interface FoodRepository extends CrudRepository<Food, Integer> {}
You need to replace spring-boot-starter-jdbc with spring-boot-starter-data-jpa as follows:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
You can have a look at the following links the difference between them, but basically, JPA helps you deal with your Database data by mapping it directly to Java objects:
https://www.baeldung.com/jpa-vs-jdbc
JPA or JDBC, how are they different?
I think you are just a little bit confused with spring-jdbc, spring-data and spring persistence interfaces abstraction, let me help. TL;DR solution is at the bottom:
In the constructor of FoodController you are declaring FoodRepository as a parameter, so spring have to find the bean of this time at runtime in order to create bean of FoodController. You have declared FoodRepository and extend it from CrudRepository. I guess, that you have done it with the assumption, that spring will create an implementation of FoodRepository at runtime (because it extends CrudRepository). But, unfortunately, it is not the spring-core module, that will create bean of FoodRepsitory, nor it is spring-jdbc. This interfaces are the part of spring-data project. So, for creation of the bean of the type FoodRepository is responsible current spring-data project in your classpath (I mean, it could be spring-data-jdbc, spring-data-jpa or whatever). This interfaces (CrudRepository, Repository e.t.c.) are common for all of the spring data projects, so they are shipped in spring-data-commons jar, this is why you have them available in classpath, because you have included spring-data-commons explicitly:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.5.1</version>
</dependency>
Another thing is that this starter:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
does not do anything with spring-data project - it just brings spring-jdbc, Hikari connection pool, and some other spring-boot stuff. In other words, the problem is that you do not have any spring-data project in your classpath, thats why FoodRepository bean is not created.
Also note: #Entity does not make sense here, becuase you do not have any jpa persistence provider in classpath
Solution:
To solve the problem, I suggest you to
Remove spring-data-commons dependency from pom.xml
Include spring-boot-starter-data-jpa into your project (into pom.xml). It will bring the appropriate version of spring-data-commons dependency.
Hope it helped, have a nice day!
Add #Repository annotation to FoodRepository interface
and also #Autowired annotation to the FoodRepository in FoodController.

Bean Validation in Spring Boot Data Rest Not Working

I have a very simple Spring Boot 2.0.3 project using Spring Data Rest.
When I try to add a User with an invalid email address using POST on http:localhost:8080/users, this JSON is returned:
{
"timestamp": "2018-08-07T18:16:15.513+0000",
"status": 500,
"error": "Internal Server Error",
"message": "Could not commit JPA transaction; nested exception is
javax.persistence.RollbackException: Error while committing the
transaction",
"path": "/users"
}
POM.XML
<modelVersion>4.0.0</modelVersion>
<groupId>in.tschud</groupId>
<artifactId>User</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>User</name>
<description>RESTful User API</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.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-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
UserApp.java
#SpringBootApplication
public class UserApplication {
public static void main(String[] args) {
SpringApplication.run(UserApplication.class, args);
}
}
User.java
#Data
#NoArgsConstructor
#Entity
public class User {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE)
private long id;
#Email
private String email;
private String firstName;
private String lastName;
private String password;
}
UserRepository.java
#RepositoryRestResource(collectionResourceRel = "users", path = "users")
public interface UserRepository extends PagingAndSortingRepository<User,
Long> {
}
I have googled and there seem to have been a number of related issues around this some years ago and I have tried the suggested solutions here
but none of these worked.
I have already spent a lot of time trying to get this to work (a lot more, than it would have taken to write a simple JAX-RS API endpoint that does the same thing), so any help would be much appreciated.
Will have to post console output below, as posts here are limited to 3000 character.
Everything you posted shows that it works as expected.
A ConstraintViolationException is raised, and the message indicates that indeed the email is invalid.
What might confuse you is that the error returned is defaulted to Http Status 500. You must not have declared an exception handler in the same controller, or a #ControllerAdvice-marked class ex :
#ResponseStatus(value=HttpStatus.BAD_REQUEST, reason="Request content invalid")
#ExceptionHandler(javax.validation.ConstraintViolationException.class)
public void error() {
// You can customize messages and extract faulty fields
}

#QuerydslPredicate throwing exception

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.
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 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>
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
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));
}
}

Unresolvable circular reference in SpringBoot

I am learning Spring Framework and now I am trying to make a simple Spring Boot application that would list all entries from a database (using Hibernate).
First I had a problem when SessionFactory would not be defined, but I managed to define it in Config Class. However, when I try to run the app now, I get the following error:
Description:
The dependencies of some of the beans in the application context form a cycle:
indexController (field private com.prvi.dao.CustomerDAO com.prvi.controllers.IndexController.customerDAO)
↓
customerDAOImpl (field private org.hibernate.SessionFactory com.prvi.dao.CustomerDAOImpl.sessionFactory)
┌─────┐
| sessionFactory defined in class path resource [com/prvi/ConfigPrvi.class]
└─────┘
Basically, I have IndexController, who gets GET / request, then it calls customerDAO to get list of customers and customerDAO uses sessionFactory to get Session and performs a query on DB. (I have omitted Service layer from the app for sake of simplicity)
Now, I have read that this error happens when a bean is dependent on a bean that is dependent on a first bean, making cyclical dependency. However, I do not understand where I made this cycle and how to fix it. Also, other answers on this topic have not provided me enough information to correct the error. They were mostly oversimplifies where cycle is clear, which is not the case here.
Here is what I have tried so far:
PrviApplication.java - entry point for Spring Boot
#SpringBootApplication
public class PrviApplication {
public static void main(String[] args) {
SpringApplication.run(PrviApplication.class, args);
}
}
ConfigPrvi.java - My Configuration file
#Configuration
#EnableAutoConfiguration
public class ConfigPrvi {
#Bean
public HibernateJpaSessionFactoryBean sessionFactory(EntityManagerFactory emf){
HibernateJpaSessionFactoryBean factory = new HibernateJpaSessionFactoryBean();
factory.setEntityManagerFactory(emf);
return factory;
}
}
IndexController.java - my Controller class, which handles GET /
#Controller
#RequestMapping("/")
public class IndexController {
#Autowired
private CustomerDAO customerDAO;
#GetMapping("/")
public String listCustomers(Model model){
model.addAttribute("customers", customerDAO.getAllCustomers());
return "index";
}
}
CustomerDAO.java - just an interface
public interface CustomerDAO {
public List<Customer> getAllCustomers();
}
CustomerDAOImpl.java - implementation, retrieves data from database
#Repository
public class CustomerDAOImpl implements CustomerDAO {
#Autowired
private SessionFactory sessionFactory;
#Transactional
public List<Customer> getAllCustomers(){
Session session = sessionFactory.getCurrentSession();
Query<Customer> query = session.createQuery("from Customer order by lastName", Customer.class);
List<Customer> customers = query.getResultList();
return customers;
}
}
Is it perhaps that cycle was made here:
main --> controller --> dao --> sessionFactory --> config --> main
If so, how can I rewrite the code so that I get rid of it?
EDIT: Added 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.prvi</groupId>
<artifactId>prvi</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>prvi</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.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-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.10.Final</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>5.2.10.Final</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Categories