Spring boot 2.1 - NoSuchMethodError - getDispatcherServlet() - spring-boot

Just upgraded from Spring Boot 2.0.6 to Spring Boot 2.1.0 and am getting this error in my existing #WebMvcTest annotated tests:
java.lang.NoSuchMethodError: org.springframework.test.web.servlet.MockMvc.getDispatcherServlet()
My test looks like this:
#RunWith(SpringRunner.class)
#WebMvcTest(value = SubscriptionsResource.class, secure = false)
#ActiveProfiles("test")
public class SubscriptionsResourceTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private SomeService someservice;
#Test
public void someTestMethod() throws Exception {
//test content
}
}
I had tried removing the secure = false in favor of #WithMockUser as suggested in release notes but have the same issue.
TIA.

This was due to me having spring-test dependency in my pom:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.7.RELEASE</version>
<scope>compile</scope>
</dependency>
Removing this resolved the issue.

Related

WebTestClient throws "No qualifying bean ... as autowire candidate"

I currently wrote a put request I wanted to test via WebTestClient. I followed some tutorials and adapted my case to it. Testing the request results in an error:
"NOSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.reactive.server.WebTestClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}"
I looked up some solutions on SO like this one: Cant autowire `WebTestClient` - no auto configuration but couldn't make it work, despite of the hints there.
Here is the test code:
#SpringBootTest
#AutoConfigureWebTestClient
public class DemonstratorApplicationTests {
private P4uServiceImpl p4uService = new P4uServiceImpl();
#Autowired
WebTestClient webTestClient;
#MockBean
ReqP4uAccount account;
#Test
void testPutAccount(){
ReqP4uAccount request = p4uService.buildRequest("testAccount");
this.webTestClient.put()
.uri("/account")
.contentType(MediaType.APPLICATION_JSON)
.body(request, ReqP4uAccount.class)
.exchange()
.expectStatus().isOk()
.expectBody(P4uAccount.class);
}
}
Has anyone an idea what's wrong with the test setup? Thx in advance
The following works:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureWebTestClient
public class DemoApplicationTests {
#Autowired
WebTestClient webTestClient;
If you remove (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT), it will fail.
If you look at the WebTestClientAutoConfiguration , you can see that it has
#ConditionalOnClass({ WebClient.class, WebTestClient.class }) and that could be why it wont work, unless Springboot starts up the web application context during (webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
/**
* Auto-configuration for {#link WebTestClient}.
*
* #author Stephane Nicoll
* #author Andy Wilkinson
* #since 2.0.0
*/
#Configuration(proxyBeanMethods = false)
#ConditionalOnClass({ WebClient.class, WebTestClient.class })
#AutoConfigureAfter({ CodecsAutoConfiguration.class, WebFluxAutoConfiguration.class })
#Import(WebTestClientSecurityConfiguration.class)
#EnableConfigurationProperties
public class WebTestClientAutoConfiguration {

Could not autowire. No beans of 'StateMachineFactory<States, Events>' type found

#Configuration
#EnableStateMachineFactory
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter
<States, Events> {
// configuring...
}
public enum Events {
CONFIRM_RESET,
CANCEL_RESET
// other events
}
public enum States {
INITIAL,
STARTING_ORDER
// other states
}
#Service
#Slf4j
public class OrderService {
#Autowired
private StateMachineFactory<States, Events> stateMachineFactory;
// Could not autowire. No beans of 'StateMachineFactory<States, Events>' type found.
}
#EnableStateMachineFactory annotation does not work. Could not autowire. No beans of StateMachineFactory<States, Events>' type found.
In the same time after using #EnableStateMachine I can autowire 1 statemachine.
oh, this is a version of boot starter problem, i change my version from 2.2.1 to 2.5.4 and the problem get away
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.5.4</version>
</dependency>
<dependency>
<groupId>org.springframework.statemachine</groupId>
<artifactId>spring-statemachine-starter</artifactId>
<version>3.0.1</version>
</dependency>
This solved my problem

Springboot Junit test NoClassDefFoundError EntityManagerFactoryBuilderImpl

I created a springboot (2) webflux project as follow :
JPA Entity
#Entity
#Table(name = "users")
public class User implements Serializable
{
...
}
Spring repository
public interface UserRepository extends CrudRepository<User, Long>
{
}
Service
#Service
public class UserService
{
#Autowired
private UserRepository userRepo;
...
}
Webflux Handler
#Component
public class UserHandler
{
#Autowired
private UserService userService;
public Mono<ServerResponse> getUser(ServerRequest request)
{
...
}
}
RouteConfiguration
#Configuration
public class RouteConfiguration
{
#Bean
public static RouterFunction<ServerResponse> userRoutes(UserHandler userHandler)
{
return RouterFunctions.route(RequestPredicates.GET("/user"), userHandler:: getUser);
}
WebApp
#SpringBootApplication
public class WebApplication
{
public static void main(String[] args)
{
SpringApplication.run(WebApplication.class);
}
}
POM
<dependencies>
<!-- Compile -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<!-- Provided -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<!-- Runtime -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Everything run fine, I can start my server and use it. I would like now to code some tests. Here is what I did :
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = WebApplication.class)
public class UserHandlerTest
{
#Autowired
private ApplicationContext context;
#MockBean
private UserService userService;
private WebTestClient testClient;
#Before
public void setUp()
{
testClient = WebTestClient.bindToApplicationContext(context).build();
}
#Test
public void testUser()
{
...
}
}
What ever I tried, I got an error with hibernate dependencies during "mvn clean install" process :
[ERROR] testUser(...UserHandlerTest) Time elapsed: 0 s <<< ERROR!
java.lang.IllegalStateException: Failed to load ApplicationContext
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: Could not initialize class org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl
I know JPA works in blocking way but I want to avoid to use NoSQL DB for this project. Did I miss something ? Thank you a lot for help !
Probably, you are missing details which we need to provide for datasource under src/main/resources. you can check https://github.com/hantsy/spring-reactive-sample/blob/master/boot-data-mongo/src/main/resources/application.yml. this might help you.
To test my Spring Webflux controllers, I finally use the WebFluxTest annotation. It works as expected :
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {RouteConfiguration.class, UserHandler.class})
#WebFluxTest
public class UserHandlerTest
{
#Autowired
private ApplicationContext context;
#MockBean(name="userService")
private UserService userService;
private WebTestClient testClient;
#Before
public void setUp()
{
testClient = WebTestClient.bindToApplicationContext(context).build();
}
...
As I do not use RestController annotation but functional endpoints I had to use ContextConfiguration and manually instantiate the WebTestClient.

JSR 303 Validator injection with Spring in Jersey classes

I encountered a strange behaviour that I didn't manage to explain, with a validator injection in a Jersey class with DI managed by Spring.
To sumerize the situation :
I'm using Jeysey 2 and Spring 4 to produce REST web services using the jax-rs specification, and I'm validating the bean with the jsr303 bean validation annotations. The bean validation implementation is Hibernate Validator, bundled within jersey-bean-validation dependency.
Here is my POM:
<jersey.version>2.26-b07</jersey.version>
...
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring4</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-bean-validation</artifactId>
<version>${jersey.version}</version>
</dependency>
In my spring configuration, I declare a Validator bean (with a custom message interpolator to retrieve the error messages in database), which I'll later want to inject in my web service classes :
#Bean
public Validator getValidator(MessageInterpolator messageInterpolator){
return Validation.byDefaultProvider().configure()
.messageInterpolator(messageInterpolator)
.buildValidatorFactory()
.getValidator();
}
At this point, I'm able to inject my validator in Jersey classes using the #Autowired annotation, but not with the jsr 330 #Inject annotation which inject another validator with the default Hibernate Validator message interpolator...
#Autowired
private Validator validator; // OK
#Inject
private Validator validator; // KO
#Inject
private OtherService otherService; // OK
Can you explain me what happen here ?
I understood that the dependency injection implementation bundled with Jersey is HK2, but the jersey-spring plugin is supposed to do the bridge between HK2 and Spring, I must have missed something because they seem completely dissociated, I think that :
#Autowired use Spring and inject the bean I've defined
#Inject use HK2 which is not aware of that bean, and inject the one found in the Hibernate Validator project...
By the way I'm perfectly able to inject my other Spring services with the #Inject annotation, that's why I'm loosing my mind and don't know what to think... The only problematic bean seems to be this Validator.
I also tried to use the #Valid annotation to validate my beans without having to inject the validator, and the problem is the same : Jersey use the default validator from Hibernate Validator...
After lots of time, I found a way to fix the #Valid problem by creating a ContextResolver Provider to modify Jersey default configuration with my custom message interpolator :
#Provider
public class ValidationConfigContextResolver implements ContextResolver<ValidationConfig> {
private final MessageInterpolator messageInterpolator;
#Inject
public ValidationConfigContextResolver(MessageInterpolator messageInterpolator) {
this.messageInterpolator = messageInterpolator;
}
#Override
public ValidationConfig getContext(Class<?> aClass) {
final ValidationConfig config = new ValidationConfig();
config.messageInterpolator(messageInterpolator);
return config;
}
}
Now Jersey use a validator with my message interpolator but I'm still trying to understand why I'm not able to inject it with the #Inject annotation in Jersey classes !
Thanks for the assistance

java.lang.NoClassDefFoundError: org/apache/commons/logging/Log while Mocking RestTemplate with Junit

I am writting a test case where i have to mock RestTemplate. But when i execute the test cases i am facing NoClassDefFoundException. Below is my code
#RunWith(MockitoJUnitRunner.class)
class X{
#InjectMocks
private YService yService;
#Mock
private RestTemplate restTemplate;
#Test
public void test(){
when(restTemplate.postForObject(Mockito.anyString(),Mockito.any(),Mockito.any())).thenReturn("HelloWorld");
}
}
Gradle is not downloading the commons-logging dependency If i try to include it as dependency in build.gradle.
Probably you may be needing apache commons logging in classpath
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>

Resources