ReflectionUtil error in Component/Functional Test with Repository layer - spring

I am trying to run a JUnit test on my Repository layer
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = {JPAConfig.class, SpringBootMainApplication.class})
public class AddBookTest {
#Autowired
private BookRepository bookRepository;
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#BeforeEach
public void setUp() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
#Sql({"/book-schema.sql", "/book-data.sql"})
void addBook() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.put("/users/")
.header("X-MC-CorrelationID", UUID.randomUUID())
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON)
.characterEncoding("UTF-8")
.content("{\"book\": \"LOTR\"}")
.andExpect(MockMvcResultMatchers.status().isNoContent())
.andDo(MockMvcResultHandlers.print());
}
private String requestBody() {
return "{\n" +
" \"book\": \"LOTR\",\n" +
"}";
}
}
I am getting the following error:
java.lang.NoSuchMethodError: 'org.springframework.util.ReflectionUtils$MethodFilter org.springframework.util.ReflectionUtils$MethodFilter.and(org.springframework.util.ReflectionUtils$MethodFilter)'
at org.springframework.test.context.junit.jupiter.SpringExtension
Version:
implementation group: "org.springframework.boot", name: "spring-boot-starter-web", version: "2.2.1.RELEASE"
implementation group: "org.springframework.boot", name: "spring-boot-starter-data-jpa", version: "2.2.1.RELEASE"
implementation group: "org.springframework.boot", name: "spring-boot-starter-actuator", version: "2.2.1.RELEASE"
testImplementation group: 'org.springframework', name: 'spring-test', version: "5.2.1.RELEASE"
implementation group: 'org.springframework', name: 'spring-context', version: "5.2.1.RELEASE"
In short, all my Spring Boot dependencies are on 2.2.1.RELEASE train while the Spring framework is 5.2.1.RELEASE. Are these versions compatible?

Its hard to say for sure what happens but is sounds like a clash of versions of spring that you have on your classpath.
This specific method "and" is pretty new see the javadoc. It explicitly states that the method is since version "5.3.2" which is pretty new.
So I suggest examining the dependency tree of jars in the test class path to understand whether you mix between a new and some older versions of Spring.

Related

Spring #DataJpaTest with JUnit 5

There doesn't seem to be a specific standard way I can find online that makes #DataJpaTest to run correctly.
Is it true that #DataJpaTest is not being used nowadays and all tests are run at the service or controller level using #SpringBootTest?
#Repository
public interface MyBeanRepository extends JpaRepository<MyBean, Long> {
}
#Configuration
#EnableJpaRepositories("com.app.repository.*")
#ComponentScan(basePackages = { "com.app.repository.*" })
public class ConfigurationRepository {
}
#Entity
public class MyBean {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private Long id;
#Version
#Column(name = "version")
private Integer version;
#NotNull
#Size(min = 2)
private String name;
}
#DataJpaTest
public class MyBeanIntegrationTest {
#Autowired
MyBeanRepository myBeanRepository;
#Test
public void testMarkerMethod() {
}
#Test
public void testCount() {
Assertions.assertNotNull(myBeanRepository , "Data on demand for 'MyBean' failed to initialize correctly");
}
}
Running using the Eclipse->Run Junit shows these logs.
java.lang.IllegalStateException: Unable to find a #SpringBootConfiguration, you need to use #ContextConfiguration or #SpringBootTest(classes=...) with your test
at org.springframework.util.Assert.state(Assert.java:73)
Running using gradle test shows the error that init failed.
FAILURE: Build failed with an exception.
* What went wrong:
Test failed.
Failed tests:
Test com.app.repository.MyBeanIntegrationTest#initializationError (Task: :test)
Here is the gradle script.
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin")
}
}
plugins {
id 'org.springframework.boot' version '2.1.5.RELEASE'
id 'java'
id 'eclipse'
}
apply plugin: 'io.spring.dependency-management'
group = 'com.app'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenLocal()
jcenter()
mavenCentral()
}
test {
useJUnitPlatform()
}
dependencies {
// This dependency is exported to consumers, that is to say found on their compile classpath
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-validation'
runtimeOnly 'org.hsqldb:hsqldb'
testImplementation ('org.springframework.boot:spring-boot-starter-test') {
// exlcuding junit 4
exclude group: 'junit', module: 'junit'
}
/**
Test Dependencies Follows
**/
// junit 5 api
testCompile "org.junit.jupiter:junit-jupiter-api:5.2.0"
// For junit5 parameterised test support
testCompile "org.junit.jupiter:junit-jupiter-params:5.2.0"
// junit 5 implementation
testRuntime "org.junit.jupiter:junit-jupiter-engine:5.2.0"
// Only required to run junit5 test from IDE
testRuntime "org.junit.platform:junit-platform-launcher"
}
EDIT:
This has been solved and committed at the same repository.
https://github.com/john77eipe/spring-demo-1-test
It was a good idea to add a Github link. I can see following issues there:
1) If you can't have a main class annotated with #SpringBootApplication, you can use:
#SpringBootConfiguration
#EnableAutoConfiguration
#ComponentScan(basePackages = "com.app.repository")
public class MySampleApplication {
}
2) Change annotations over your ConfigurationRepository class to:
#EnableJpaRepositories("com.app.repository")
#ComponentScan(basePackages = { "com.app.repository" })
public class ConfigurationRepository {
That should let us proceed to the next point:
3) Your MyBeanIntegrationTest should be annotated as:
#SpringBootTest(classes = MyAppApplication.class)
public class MyBeanIntegrationTest {
4) In application.yml you have a small issue with indentation in the last line. Convert tab so spaces and it should be fine.
5) Next thing is MyBeanRepository interface. You can't use a method named findOne there. Thing is, that in interfaces marked as JpaRepository or CrudRepository and so on, methods names need to follow certain rules. If you mark that it will be a repository containing type MyBean your method name should be changed to findById, because Spring will look for a property named id in your bean. Naming it by findOne will cause test to fail with:
No property findOne found for type MyBean!
After fixing these things, your tests pass on my env.
I hope this helps!

Spring boot and Spring data no bean found entityMangerFactory

I've got a Spring boot application with enabled autoconfiguration.
My application is divided into 4 modules core, model, rest and repository.
Repository module uses Spring data and Hibernate. It is a module that contains all class entities and all spring data repositories.
The problem is that my application cannot find EntityManagerFactory that to my mind should be created by autoconfiguration based on added Hibernate dependency.
What error I get is:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'entityManagerFactory' available
here is my main gradle configuration:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:2.0.5.RELEASE")
}
}
plugins {
id 'java'
id 'idea'
id 'org.springframework.boot' version "2.1.0.RELEASE"
id 'io.spring.dependency-management' version "1.0.6.RELEASE"
id 'net.ltgt.apt' version '0.9'
}
group 'com.wat'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
compile project(':core')
compile project(':model')
compile project(':rest')
compile project(':repository')
compile group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.1.0.RELEASE'
compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.1'
compile "org.mapstruct:mapstruct-jdk8:1.2.0.Final"
apt "org.mapstruct:mapstruct-processor:1.2.0.Final"
testCompile group: 'junit', name: 'junit', version: '4.12'
}
allprojects {
apply plugin: "java"
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.2'
compile group: 'org.springframework', name: 'spring-context', version: '5.1.1.RELEASE'
compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.1.0.RELEASE'
compile "org.mapstruct:mapstruct-jdk8:1.2.0.Final"
compile "org.mapstruct:mapstruct-processor:1.2.0.Final"
}
}
my main class
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
My repository module gradle file:
plugins {
id 'net.ltgt.apt'
}
dependencies {
compile group: 'org.springframework.data', name: 'spring-data-jpa', version: '2.1.2.RELEASE'
compile group: 'org.hibernate', name: 'hibernate-core', version: '5.3.7.Final'
compile 'mysql:mysql-connector-java:8.0.13'
compile project(":model")
testCompile group: 'junit', name: 'junit', version: '4.12'
}
and my repository module configuration class:
#Configuration
#EnableJpaRepositories(basePackages = "com.wat.zpm.repository")
#EnableTransactionManagement
#EnableAutoConfiguration
public class RepositoryConfiguration {
}
According to what I found out is that spring autoconfigurer automatically creates bean EntityManagerFactory based on classpath classes so everything should work fine with given annotations.
What is more autoconfiguration logging says that HibernateJpaAutoConfiguration was matched.
The class that misses the EntityManagerFactory:
#Repository
public class UserRepositoryServiceImpl implements UserRepositoryService {
private final UserEntityMapper userMapper;
private final UserRepository userRepository;
public UserRepositoryServiceImpl(UserEntityMapper userMapper, UserRepository userRepository1) {
this.userMapper = userMapper;
this.userRepository = userRepository1;
}
}
UserRepository is a interface that extends JpaRepository
I've made a research and couldn't found annotation or dependency that my project could possibly miss.
You are missing #ComponantScan in RepositoryConfiguration class.
here is the great explanation of componentscan annotation.

New Functional Web Framework with jetty

I wanted to setup an example for New in Spring 5: Functial Web Framework
So I set up a RouteConfiguration:
#Configuration
public class RouteConfiguration {
#Autowired
private MyService myService;
#Bean
public RouterFunction<?> routerFunction() {
return route(
GET("/first")
, myService::getItemsFirst)
.and(route(
GET("/second")
, myService::getItemsSecond));
}
}
I started my application using jetty and at first it seemed to work... until I wanted to call one of my methods: localhost:8080/first and it returned a 404.
Did I define my route configuration wrong or why arent the routes accessible?
EDIT
With netty you need to provide a Server Configuration Like the following:
#Configuration
public class HttpServerConfiguration {
#Autowired
private Environment environment;
#Bean
public HttpServer httpServer(final RouterFunction<?> routerFunction) {
final HttpHandler httpHandler = RouterFunctions.toHttpHandler(routerFunction);
final ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
final HttpServer server = HttpServer.create("localhost", Integer.valueOf(this.environment.getProperty("server.port")));
server.newHandler(adapter);
return server;
}
}
But I could not find something like this for jetty.
EDIT 2
My Dependencies:
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencyManagement {
dependencies {
dependency (group: 'org.springframework.cloud', name: 'spring-cloud-starter-consul-discovery', version: '2.0.0.M1')
dependencySet (group: 'org.hibernate', version: '5.2.8.Final') {
entry 'hibernate-core'
entry 'hibernate-entitymanager'
entry 'hibernate-spatial'
}
}
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-hateoas')
compile('org.springframework.boot:spring-boot-starter-jetty')
compile('org.springframework.boot:spring-boot-starter-webflux') {
exclude module: 'spring-boot-starter-reactor-netty'
}
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.boot:spring-boot-autoconfigure')
compile('org.springframework.boot:spring-boot-actuator')
compile('org.springframework.cloud:spring-cloud-starter-consul')
compile('org.springframework.cloud:spring-cloud-starter-consul-discovery')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('junit:junit')
}
Spring-Boot Version: 2.0.0.M3
Reading the comments, it seems this was an issue with dependencies bringing spring-boot-starter-web; if it is present, a Spring MVC application is started by Spring Boot.
There's a way to explicitly tell Spring Boot the type of the application, in the main Application class:
public static void main(String[] args) {
SpringApplication application = new SpringApplication(AgentApplication.class);
application.setWebApplicationType(WebApplicationType.REACT‌​IVE);
application.run(args);
}

The dreadful "Unable to start EmbeddedWebApplicationContext" error

I have the following exception when trying to run integration test:
org.springframework.context.ApplicationContextException: Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean.
I read many forum entries but not found any solution. My files are as follows:
Integration test
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, classes = WebInitializer.class)
#DataJpaTest
#Sql("/db/data.sql")
public class ReportEventIntTest {
#Autowired
private TestRestTemplate restTemplate;
#Test
public void reportEvent() {
Map<String, String> eventMap = new HashMap<>();
this.restTemplate.postForEntity("/worker/event", eventMap, String.class);
}
}
Spring Boot config
#Configuration
#ComponentScan(basePackages = {"org.reaction.engine.collector.controller",
"org.reaction.engine.persistence.service",
"org.reaction.engine.persistence.converter",
"org.reaction.engine.service"})
#EnableAutoConfiguration
#ImportResource("classpath:applicationContext.xml")
#Profile("threadPool") // define the default profile: it can be overridden by -Dspring.profiles.active=...
public class WebInitializer extends SpringBootServletInitializer implements WebApplicationInitializer {
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(WebInitializer.class);
}
public static void main(String[] args) throws Exception {
SpringApplication.run(WebInitializer.class, args);
}
#Bean
public EmbeddedServletContainerFactory servletContainer() {
TomcatEmbeddedServletContainerFactory factory = new TomcatEmbeddedServletContainerFactory();
return factory;
}
}
Gradle file
apply plugin: 'org.springframework.boot'
apply plugin: 'war'
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.4.3.RELEASE'
}
}
dependencies {
compile project(':common')
compile 'org.springframework:spring-context-support'
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-web'
compile 'org.springframework.boot:spring-boot-starter-data-jpa'
compile 'org.springframework.boot:spring-boot-starter-integration'
compile 'org.springframework.boot:spring-boot-starter-actuator'
compile 'org.apache.httpcomponents:httpclient:4.5.2'
providedRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
providedCompile 'javax.enterprise.concurrent:javax.enterprise.concurrent-api:1.0'
runtime 'mysql:mysql-connector-java'
// ---------------------- TESTING ----------------------
testCompile 'com.jayway.restassured:rest-assured:2.9.0'
testCompile 'org.springframework.boot:spring-boot-starter-test'
//testRuntime 'org.hsqldb:hsqldb'
testRuntime 'com.h2database:h2'
testRuntime 'org.springframework.boot:spring-boot-starter-tomcat'
}
Any idea?
I would greatly appreciate any thought!
Regards,
V.
I read many stackoverflow entries but I missed the following one:
#Profile cause Unable to start EmbeddedWebApplicationContext
The problem is that I defined the profile in my spring boot config class but I have to do that in the test class.
#ActiveProfiles("threadPool")

JSR-303 bean validation with Spring does not kick in

I've configured a JSR-303 custom validator following what's given in the docs (http://docs.spring.io/spring/docs/4.0.x/spring-framework-reference/html/validation.html), complete with LocalValidatorFactoryBean and Hibernate validator on the classpath. However, my validator just refuses to kick in. I've put up a dirt simple test project here (https://github.com/abhijitsarkar/java/tree/master/spring-jsr-303), along with a failing unit test. Should you decide to take a look, just clone it and run
gradlew clean test from the root directory.
I'm using Spring framework 4.0.2.RELEASE and Hibernate validator 5.0.3.Final.
Method under validation:
public Coffee serve(#ValidOrder(Coffee.Blend.class) final String blend) {
ValidOrder annotation:
#Documented
#Constraint(validatedBy = {OrderValidator.class})
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD,
ElementType.FIELD,
ElementType.ANNOTATION_TYPE,
ElementType.CONSTRUCTOR,
ElementType.PARAMETER})
#NotNull
public #interface ValidOrder {
OrderValidator validator:
public class OrderValidator implements ConstraintValidator<ValidOrder, String> {
Spring config:
#Configuration
#ComponentScan(basePackages = "name.abhijitsarkar.coffeehouse")
#EnableAspectJAutoProxy
public abstract class AppConfig {
#Bean
public LocalValidatorFactoryBean validator() {
return new LocalValidatorFactoryBean();
}
}
Dependencies:
dependencies {
compile(
[group: 'javax.inject', name: 'javax.inject', version: injectApiVersion],
[group: 'javax.validation', name: 'validation-api', version: beanValidationApiVersion],
[group: 'javax.annotation', name: 'javax.annotation-api', version: annotationApiVersion],
[group: 'org.springframework', name: 'spring-beans', version: springVersion],
[group: 'org.springframework', name: 'spring-context', version: springVersion],
[group: 'org.springframework', name: 'spring-aop', version: springVersion],
[group: 'org.aspectj', name: 'aspectjrt', version: aspectjVersion]
)
runtime(
[group: 'org.hibernate', name: 'hibernate-validator', version: hibernateValidatorVersion],
[group: 'javax.el', name: 'javax.el-api', version: elVersion],
[group: 'org.glassfish.web', name: 'javax.el', version: glassfishElVersion],
[group: 'org.aspectj', name: 'aspectjweaver', version: aspectjVersion]
)
A MethodValidationPostProcessor needs to be configured in addition to the LocalValidatorFactoryBean.
The class to be validated must have a #Validated annotation on it else methods are NOT searched for inline constraint annotations.
#Configuration
#ComponentScan(basePackageClasses = {SpringPackageComponentScanMarker.class})
#EnableAspectJAutoProxy
public abstract class AppConfig {
#Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
final MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
#Bean
public LocalValidatorFactoryBean validator() {
final LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
return localValidatorFactoryBean;
}
}
...
#Service
#Validated
public class SpringBarista extends Barista {
The part of the reference manual that talks about integration with JSR-303 conveniently omits these 2 crucial points without which BV does not kick in. This just caused me 6 hours of debugging and hair tearing where I did everything the doc said but BV would simply not kick in. I finally had to debug through the Spring source code to understand this. There got to be an easier way and I can't be the only one who had this problem. Created a JIRA SPR-11473 for them to update the doc.
For spring to validation to kick in the blend argument needs a #Valid annotation in front of it.
Your approach might not work since parameter contraints are not supported by the JSR303.
Constraint annotations can target any of the following ElementTypes:
FIELD for constrained attributes
METHOD for constrained getters
TYPE for constrained beans
ANNOTATION_TYPE for constraints composing other constraints
http://beanvalidation.org/1.0/spec/#constraintsdefinitionimplementation

Resources