I'm creating a web application using spring-boot with annotation based configuration.
At first, I created a spring application with annotation based config using Hibernate and JPA. It was working fine but then I needed to add spring-boot to my application and now cannot start it. Here is the code:
#SpringBootApplication
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class Runner {
public static void main(String[] args) {
SpringApplication.run(Runner.class, args);
}
}
#Configuration
#EnableTransactionManagement
#ComponentScans(value = { #ComponentScan("com.alex.pharm.dao"),
#ComponentScan("com.alex.pharm.service") })
public class AppConfig {
#Bean
public LocalEntityManagerFactoryBean geEntityManagerFactoryBean() {
LocalEntityManagerFactoryBean factoryBean = new LocalEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName("LOCAL_PERSISTENCE");
return factoryBean;
}
#Bean
#ConditionalOnMissingBean(type = "JpaTransactionManager")
public JpaTransactionManager geJpaTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(geEntityManagerFactoryBean().getObject());
return transactionManager;
}
}
#RestController
public class HelloController {
#RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
<groupId>com.sachatol.pharmacy</groupId>
<artifactId>pharmacyWebStore</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.1</version>
</dependency><!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.13</version>
</dependency>
<!-- Hibernate 5.2.9 Final -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.9.Final</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>4.3.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
But when I try to run it I get the following exception:
ConfigServletWebServerApplicationContext : Exception encountered during context initialization
- cancelling refresh attempt:org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'requestMappingHandlerMapping'
defined in class path resource
[org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]:
Initialization of bean failed; nested exception is java.lang.NoSuchMethodError:
org.springframework.web.servlet.handler.AbstractHandlerMapping.obtainApplicationContext()
Lorg/springframework/context/ApplicationContext;
How can I fix it?
Issue found - I used the old version for spring-context in pom (4.3.7.RELEASE) which override the one that spring-boot has and was the reason of NoSuchMethodError. So spring-context dependency was old and obsolete after removing or changing it to newer version (5.0.3) application started fine
Your #RequestMapping seems missing some parts, try with something like that:
#RequestMapping(value = "/", method = RequestMethod.GET)
This also happens if you have two methods with same request mapping values. Make sure you have unique RequestMapping values.
In your request mapping, you have incorrectly used :
#RequestMapping("/")
Instead, use this mapping to specify the end-point and the request-method like this :
#RequestMapping(value = "/", method = RequestMethod.GET)
Hope it will solve your problem.
Related
After I added dependency for HATEOAS to Maven, Spring Boot does not start:
Added dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
Full 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.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>ru.example</groupId>
<artifactId>testapp</artifactId>
<version>1.0</version>
<name>testapp</nAfter I added dependency for HATEOAS to Maven, Spring Boot does not startame>
<description>Test</description>
<properties>
<java.version>1.8</java.version>
<h2.version>1.4.200</h2.version>
<jackson-json.version>2.10.2</jackson-json.version>
<jsoup.version>1.12.1</jsoup.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-hateoas</artifactId>
</dependency>
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.17.Final</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>5.3.0.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson-json.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
<version>${jackson-json.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>${jackson-json.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SecurityConfig.class:
package ru.example.testapp;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import ru.example.testapp.dao.UserRepository;
import ru.example.testapp.service.UserServiceImpl;
#Configuration
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final UserRepository userRepository;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(new UserServiceImpl(userRepository))
.passwordEncoder(new BCryptPasswordEncoder());
}
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/rest/admin/**").hasRole("ADMIN").and().httpBasic().and()
.authorizeRequests()
.antMatchers("/rest/user/**").hasAnyRole("USER","ADMIN").and().httpBasic().and()
.authorizeRequests().and()
.csrf().ignoringAntMatchers("/rest/**");
}
}
JacksonObjectMapper.class:
package ru.example.testapp.util.json;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.stereotype.Component;
#Component
public class JacksonObjectMapper extends ObjectMapper {
private static final ObjectMapper MAPPER = new JacksonObjectMapper();
public static ObjectMapper getMapper() {
return MAPPER;
}
private JacksonObjectMapper() {
registerModule(new Hibernate5Module());
registerModule(new JavaTimeModule());
configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
}
In console I have following error:
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'securityConfig': Unsatisfied dependency
expressed through method 'setContentNegotationStrategy' parameter 0;
nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name
'org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration$EnableWebMvcConfiguration':
Unsatisfied dependency expressed through method 'setConfigurers'
parameter 0; nested exception is
org.springframework.beans.factory.UnsatisfiedDependencyException:
Error creating bean with name 'hypermediaWebMvcConfigurer' defined in
class path resource
[org/springframework/hateoas/config/WebMvcHateoasConfiguration.class]:
Unsatisfied dependency expressed through method
'hypermediaWebMvcConfigurer' parameter 0; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'hypermediaWebMvcConverters' defined in class
path resource
[org/springframework/hateoas/config/HateoasConfiguration.class]: Bean
instantiation via factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [org.springframework.hateoas.config.WebConverters]:
Factory method 'hypermediaWebMvcConverters' threw exception; nested
exception is java.lang.IllegalStateException: Failed copy():
ru.example.wmanage.util.json.JacksonObjectMapper (version: 2.10.2)
does not override copy(); it has to
What could be the problem?
In error - something with securityConfig, JacksonObjectMapper and hateoas.
If I delete spring-boot-starter-hateoas at dependencies, then all works. But I need hateoas.
Please help.
UPDATED:
The problem occurs when using custom JacksonObjectMapper with annotation #Component. As soon as spring-boot-starter-hateoas added to dependencies, then Spting Boot does not startup.
QUESTION: How to use custom JacksonObjectMapper and hateoas together?
PROBLEM NOT RESOLVED
I don't think you have any reason to be extending ObjectMapper. You should instantiate an ObjectMapper like normal and then configure it by its exposed methods and register it as a bean in your configuration.
#Bean
public ObjectMapper createMapper() {
return new ObjectMapper().registerModule(new Hibernate5Module());
.registerModule(new JavaTimeModule());
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE);
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
.setSerializationInclusion(JsonInclude.Include.NON_NULL);
}
I dont know why one should not extend ObjectMapper.
probably Deadron Mar can explain, but this class is not final.
In my case it is extended deeply in our corporal framework and i got same error message.
i just did another extension
#Component
public class MyCustomizedMapper extends AnotherExtendedMapper {
public MyCustomizedMapper copy() {
return new MyCustomizedMapper(); // we have default constructor for this
` }
}
and wonder - it works)
Using liquibase and springboot , created db changelogs and able to run it successfully with maven-liquibase-plugin (mvn liquibase:update). I'm writing integration tests , in which liquibase changes needs to be created programmatically .
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = DummyApplication.class)
#ActiveProfiles("test")
public class TestDummyService
{
#Autowired
private SpringLiquibase springLiquibase;
...
#Test
public void testDummyRequest()
{
try {
Connection connection = springLiquibase.getDataSource().getConnection();
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
Liquibase liquibase = new liquibase.Liquibase("liquibase/changelog/db-changelog-master.xml", new ClassLoaderResourceAccessor(), database);
liquibase.update(new Contexts(springLiquibase.getContexts()), new LabelExpression(springLiquibase.getLabels()));
} catch (LiquibaseException | SQLException e) {
e.printStackTrace();
}
}
Getting the below exception while running the above test.
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:125)
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'liquibase' defined in class path resource [org/springframework/boot/autoconfigure/liquibase/LiquibaseAutoConfiguration$LiquibaseConfiguration.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [liquibase.integration.spring.SpringLiquibase]:
Factory method 'liquibase' threw exception; nested exception is java.lang.NoSuchMethodError: liquibase.integration.spring.SpringLiquibase.setLiquibaseSchema(Ljava/lang/String;)V
Caused by: java.lang.NoSuchMethodError: liquibase.integration.spring.SpringLiquibase.setLiquibaseSchema(Ljava/lang/String;)
below is application-test.property file .
#NOTE : spring.liquibase is the working one .
liquibase.changeLog=classpath:liquibase/changelog/db-changelog-master.xml
liquibase.enabled=true
liquibase.url=jdbc:h2:mem:cpass;DB_CLOSE_DELAY=-1
liquibase.user=root
liquibase.password=
spring.liquibase.dropFirst=true
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
jdbc.driverClassName=org.h2.Driver
spring.liquibase.enabled=true
spring.liquibase.change-log=classpath:liquibase/changelog/db-changelog-master.xml
#spring.liquibase.driver=com.mysql.jdbc.Driver
spring.liquibase.url=jdbc:mysql://localhost:3306/dummy
spring.liquibase.user=root
spring.liquibase.password=
**pom.xml : **
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.1.3.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.15</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-core</artifactId>
<version>3.4.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.1.3.RELEASE</version>
</plugin>
<plugin>
<groupId>org.liquibase</groupId>
<artifactId>liquibase-maven-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<propertyFile>liquibase/liquibase.properties</propertyFile>
<changeLogFile>liquibase/changelog/db-changelog-master.xml</changeLogFile>
</configuration>
</plugin>
</plugins>
</build>
Is there anything Im missing in the test class or any sample project url is also much helpful . Im new to springboot and liquibase .
Spring Boot 2.1.3 depends on Liquibase 3.6.3, but you have specified 3.4.2 in your pom.xml.
Having said that, Spring Boot's Liquibase autoconfiguration will do everything you've written yourself in your unit test because you've already created the properties to activate the autoconfiguration. You could delete all of the code in the test method and just #Autowire a DataSource into the test class instead. Spring will apply the Liquibase changelog for you.
One last thing: if you can, it would be better to add a <parent> to your pom.xml which means you won't need to specify the individual versions of each dependency (including Liquibase). Spring Boot has a lot of dependencies and it's a lot of work keeping the versions in sync when you upgrade. This would also have prevented your NoSuchMethodError.
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));
}
}
I'm trying to structure a project to connect to MongoDB using Spring Data as below:
SpringMongoConfig.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.SimpleMongoDbFactory;
import com.mongodb.MongoClient;
#Configuration
public class SpringMongoConfig {
#Bean
public MongoDbFactory mongoDbFactory() throws Exception {
return new SimpleMongoDbFactory(new MongoClient("127.0.0.1"), "ReconInput");
}
#Bean
public MongoTemplate mongoTemplate() throws Exception {
MongoTemplate mongoTemplate = new MongoTemplate(mongoDbFactory());
return mongoTemplate;
}
}
ReconInputRepository.java:
#Repository
public interface ReconInputRepository extends MongoRepository<ReconInput, String> {
public List<ReconInput> findByReportingDate(String reportingDate);
}
ReconInputService.java
public interface ReconInputService {
public List<ReconInput> getInputByReportingDate(String reportingDate);
}
ReconInputServiceImpl.java
#Service
public class ReconInputServiceImpl implements ReconInputService {
#Autowired
private ReconInputRepository reconInputRepository;
public List<ReconInput> getInputByReportingDate(String reportingDate) {
return reconInputRepository.findByReportingDate(reportingDate);
}
}
App.java
public class App
{
public static void main( String[] args )
{
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);
ReconInputService reconInputService = ctx.getBean(ReconInputService.class);
List<ReconInput> inputData = reconInputService.getInputByReportingDate("2017 Nov 20");
System.out.println(inputData.get(0).getReportId());
}
}
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>ups.mongodb</groupId>
<artifactId>MongoConnection</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MongoConnection</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>5.0.1.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mongodb/mongo-java-driver -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.5.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
</project>
When I run the project, it throw an exception:
No qualifying bean of type 'ups.mongo.service.ReconInputService'
available.
Please help me any suggestion for this error. Thank you !
Update 1
Added #ComponentScan(basePackages = "ups.mongo") to SpringMongoConfig.java.
Then I got new issue:
Error creating bean with name 'ReconInputService': Unsatisfied dependency expressed through field 'reconInputRepository';
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'ups.mongo.repository.ReconInputRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Update 2
Instead of using Spring Data MongoRepository. I replaced ReconInputRepository.java that extends from Spring data by implement it by myself as below :
ReconInputRepository.java
public interface ReconInputRepository {
public List<ReconInput> findByReportingDate(String reportingDate);
}
ReconInputRepositoryImpl.java
#Repository
public class ReconInputRepositoryImpl implements ReconInputRepository {
#Autowired
MongoTemplate mongoTemplate;
public List<ReconInput> findByReportingDate(String reportingDate) {
List<ReconInput> reconInputList = null;
Query searchUserQuery = new Query(Criteria.where("reportingDate").is(reportingDate));
reconInputList = mongoTemplate.find(searchUserQuery, ReconInput.class);
return reconInputList;
}
}
Then it work correctly.
My Summary
The issue may come from Spring does not support inject interface - as #amdg suggest (but work in spring boot - I have no idea why, if someone know that please leave me some comment).
Reference: Spring interface injection example
Update 3
At last, I found the most simple way to make it correctly.
All I need to do is adding #EnableMongoRepositories({ "ups.mongo.repository" }) to the SpringMongoConfig.java
As I suspected, you mix plain old Spring with Spring Boot and want to get Spring Boot effect.
In order to use Spring Boot you should update your dependencies to use Spring Boot Starters.
<?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>ups.mongodb</groupId>
<artifactId>MongoConnection</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>MongoConnection</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.8.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</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Then just add your config in the root package of your app (presumably it's ups.mongo):
#SpringBootApplication
#EnableMongoRepositories
public class App
{
public static void main( String[] args )
{
ConfigurableApplicationContext ctx = SpringApplication.run(App.class, args);
ReconInputService reconInputService = ctx.getBean(ReconInputService.class);
List<ReconInput> inputData = reconInputService.getInputByReportingDate("2017 Nov 20");
System.out.println(inputData.get(0).getReportId());
}
}
In this case, you do not even need SpringMongoConfig.class. Instead, add the following config in your application.properties:
spring.data.mongodb.host=127.0.0.1
spring.data.mongodb.port=27017
spring.data.mongodb.database=demo
Since you have annotated #Service on ReconInputServiceImpl so,
please add ReconInputServiceImpl.class in main class
ReconInputService reconInputService = ctx.getBean(ReconInputServiceImpl.class);
You can annotate your ReconInputServiceImpl class as #Service("reconInputService").
You can then access it as follows.
ReconInputService reconInputService = ctx.getBean("reconInputService",ReconInputService.class);
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringMongoConfig.class);
If you use above constructor, DI container will only load bean definitions from SpringMongoConfig class.
If You want DI container to scan all bean definitions recursively for a particular base package please use this constructor instead
AnnotationConfigApplicationContext(java.lang.String... basePackages)
I have previously added only spring-data-mongodb package which kept me busying debugging for "No qualifying bean for some repository".
After adding spring-boot-starter-data-mongodb, everything is handled by spring.
application.yaml
spring:
data:
mongodb:
uri: mongodb://username:password#localhost:27017
database: test
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
</dependency>
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>