Springboot Junit test NoClassDefFoundError EntityManagerFactoryBuilderImpl - spring-boot

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.

Related

Spring-Batch using MySql and Spring-Data Key-Value together

I have PoC to test Spring-Batch with MySql and Key-Value together.
POM
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-keyvalue</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
Application
#SpringBootApplication
#EnableMapRepositories
public class SpringBatchPocApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBatchPocApplication.class, args);
}
}
application.properties
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
spring.jpa.hibernate.ddl-auto=update
spring.datasource.url=jdbc:mysql://localhost:3307/pocdb
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.sql.init.platform=mysql
file.input=animal-list.csv
spring.batch.job.enabled=false
spring.batch.jdbc.initialize-schema=always
key-value entity
#Data
#Builder(setterPrefix = "with")
#NoArgsConstructor
#AllArgsConstructor
#KeySpace("imAnimal")
public class IMAnimal {
#Id
private UUID id;
private String name;
private String type;
private boolean processed;
}
key-value repository
#Repository
public interface IMAnimalRepository extends CrudRepository<IMAnimal, UUID> {
}
Than I have a service to controll key-value repository:
#Service
public class DatabaseService {
#Autowired
private IMAnimalRepository repository;
...
Yet, when I run my application, the IMAnimalRepository is not found by spring context.
Field repository in name.jikra.springbatchpoc.service.DatabaseService required a bean of type 'name.jikra.springbatchpoc.repository.IMAnimalRepository' that could not be found.
My guess is, there is a collision with JPA dataSource or something like this.
Is there a way to put it together?

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

spring boot fails to start-- define a bean of type 'TopicRepository' in configuration

I was following this JavaBrains tutorials of Spring Boot.
My project structure is as follows:
CourseApiApp.java:
#SpringBootApplication
#ComponentScan(basePackages = {
"com.bloodynacho.rishab.topics"
})
#EntityScan("com.bloodynacho.rishab.topics")
public class CourseApiApp {
public static void main(String[] args) {
SpringApplication.run(CourseApiApp.class, args);
}
}
TopicController.java:
#RestController
public class TopicController {
#Autowired
private TopicService topicService;
#RequestMapping(
value = "/topics"
)
public List<Topic> getAllTopcs() {
return topicService.getAllTopics();
}
}
TopicService.java:
#Service
public class TopicService {
#Autowired
private TopicRepository topicRepository;
public List<Topic> getAllTopics() {
List<Topic> topics = new ArrayList<>();
this.topicRepository
.findAll()
.forEach(topics::add);
return topics;
}
}
Topic.java:
#Entity
public class Topic {
#Id
private String id;
private String name;
private String description;
}
TopicRepository.java:
#Repository
public interface TopicRepository extends CrudRepository<Topic, String>{
}
pom.xml:
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</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>
I was using the lombok #Getter, #Getter and #AllArgsConstructor in Topic.java but I removed it after reading one of the answers here.
I read this1, this2, this3
Still, I get
***************************
APPLICATION FAILED TO START
***************************
Description:
Field topicRepository in com.bloodynacho.rishab.topics.TopicService required a bean of type 'com.bloodynacho.rishab.topics.TopicRepository' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.bloodynacho.rishab.topics.TopicRepository' in your configuration.
Process finished with exit code 1
EDIT: I read this explaining how even without actually implementing the interface the #Autowired works. I understand the solution, but I don't understand how to solve my issue. Clearly, there is some problem with the way Spring Data is set up and configured (as mentioned in the answer)
Because if your other packages hierarchies are below your main application with the #SpringBootApplication annotation, you’re covered by implicit components scan.
Therefore, one simple solution can be done by following 2 steps:
Rename the package of main class to be com.bloodynacho.rishab.
(That is what I suggest that the complete package name of main app. is supposed to be root of other packages.)
Remove #ComponentScan and #EntityScan annotation.
(Although #ComponentScan is different from #EntityScan, it can be also removed in my experience.)

Spring test: ApplicationContext configuration classes (spring data mongodb)

I only want to test mongo related code. This is my test code snippet:
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = {MongoConfig.class})
#SpringBootTest
public class ModelTest {
#Autowired
private MongoTemplate mongoTemplate;
As you can see I'm using #ContextConfiguration in order to only load Mongo related configuration:
#Configuration
public class MongoConfig {
#Bean
public CustomConversions customConversions(){
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new ReferenceWriterConverter());
return new MongoCustomConversions(converters);
}
}
As you can see it's only intented to load custom converters are going to be used by mongoTemplate in order to serialize objects to mongodb database.
Also, src/test/resources/application.properties is:
spring.data.mongodb.host: localhost
spring.data.mongodb.port: 27017
The problem is that when I'm trying to run test it's getting me an Unsatisfied dependency expressed through field 'mongoTemplate':
UnsatisfiedDependencyException: Error creating bean with name 'net.gencat.transversal.repositori.digital.mongo.ModelTest': Unsatisfied dependency expressed through field 'mongoTemplate'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.data.mongodb.core.MongoTemplate' available
Related project 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-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
Any ideas?
Seems issue you are trying to load custom mongo configuration #Bean client here or extend AbstractMongoConfiguration.
change your database name here instead of demo
#Configuration
public class MongoConfig extends AbstractMongoConfiguration {
#Override
protected String getDatabaseName() {
return "demo";
}
#Override
public MongoClient mongoClient() {
return new MongoClient("localhost", 27017);
}
#Bean
public CustomConversions customConversions(){
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new ReferenceWriterConverter());
return new MongoCustomConversions(converters);
}
}

How to enable basic caching with Spring Data JPA

I am trying to enable basic caching with Spring Data JPA. But I cannot understand why the DAO methods are still querying the database instead of using the cache.
Given the following Spring Boot 1.5.1 application
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
#SpringBootApplication
#EnableCaching
public class Server{
public static void main(String[] args) {
SpringApplication.run(Server.class, args);
}
}
Controller
#Controller
public class PasswordsController {
#Autowired
private PasswordService service;
#SuppressWarnings("unchecked")
#RequestMapping("/passwords.htm")
public void passwords(Map model,
HttpServletRequest request) {
model.put("passwords", service.getPasswords(request));
}
...
Service
#Service
#Transactional
public class PasswordService extends BaseService {
#Autowired
private PasswordJpaDao passwordDao;
public Collection<Password> getPasswords(HttpServletRequest request) {
Collection<Password> passwords = passwordDao.getPasswords(params);
return passwords;
}
...
Interface
#Transactional
public interface PasswordJpaDaoCustom {
public Collection<Password> getPasswords(PasswordSearchParameters params);
}
and implementation
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.transaction.Transactional;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import com.crm.entity.Password;
import com.crm.search.PasswordSearchParameters;
#Transactional
#Repository
public class PasswordJpaDaoImpl implements PasswordJpaDaoCustom {
#PersistenceContext
private EntityManager em;
#Override
#Cacheable("passwords")
public Collection<Password> getPasswords(PasswordSearchParameters params) {
System.err.println("got here");
return em.createQuery(hql, Password.class);
}
...
Maven Dependencies
<!-- Spring Boot start -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</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-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</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-cache</artifactId>
</dependency>
<!-- Spring Boot end -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
</dependency>
I understand that Spring Boot will implicitly use ConcurrentHashMap for caching without any specific configuration necessary?
But the getPasswords() dao method is always called instead of using the cache. Why is this?
Yes, spring boot by default uses ConcurrentHashMap for caching and the issue with your code is that you did not set any key for your passwords cache, so it is calling the database every time for fetching the data.
So you need to the key (any unique identifier) using the params object variables as shown below:
#Cacheable(value="passwords", key="#params.id")//any unique identifier
public Collection<Password> getPasswords(PasswordSearchParameters params) {
System.err.println("got here");
return em.createQuery(hql, Password.class);
}

Resources