Spring Boot basic Cacheing is Not working for me - java

I am trying to do a simple cache of data but everytime I test it. It never seems to cache the data.
package app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.concurrent.ConcurrentMapCacheManager;
import org.springframework.context.annotation.Bean;
#EnableAutoConfiguration
#SpringBootApplication
#EnableCaching
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public CacheManager cacheManager() {
return new ConcurrentMapCacheManager("getUserInfo");
}
}
package app.cache;
import app.repo.User.User;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Service
public class UserService {
private User userInfo;
#CacheEvict("getUserInfo")
public void setUserInfo(User userInfo) {
this.userInfo = userInfo;
}
#Cacheable("getUserInfo")
public User getUserInfo() {
return userInfo;
}
}
package app.controllers;
import app.cache.UserService;
import app.repo.User.Player;
import app.repo.User.User;
import app.repo.User.UserRepo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
#RestController
public class UserController {
#Autowired
private UserService userCache;
#RequestMapping("/test-user-cache")
#ResponseBody
public User testUserCache() {
if(userCache.getUserInfo() != null) {
return userCache.getUserInfo();
}
User user = new User("joejoe","wordpass");
user.setId(44444444);
userCache.setUserInfo(user);
return userCache.getUserInfo();
}
}
Dependencies
...
<dependencies>
<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>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.apache.directory.server</groupId>
<artifactId>apacheds-server-jndi</artifactId>
<version>1.5.5</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
</dependencies>
...
It doesnt seem to save the data when I try to save it. And when I do a request again, no data is never cached.

You get that behavior because the cache works. The data is saved, but null is already cached: if(userCache.getUserInfo()
In order to clear the cache when you set the value you can annotate the setUserInfo Method with #CacheEvict(cacheNames="books", allEntries=true).

Related

Why dependency injection only work on #Service and #Contract, how to change or add some other annotation like #Singleton

There is an application that is configured by hk2 dependency injection.
the pom.xml :
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<java.version>17</java.version>
<junit.version>5.4.0</junit.version>
<jsonassert.version>1.5.0</jsonassert.version>
<jersey.version>3.0.2</jersey.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>${jersey.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- Grizzly 2 HTTP Server -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-http</artifactId>
</dependency>
<!-- Jersey DI and core-->
<dependency>
<groupId>org.glassfish.jersey.inject</groupId>
<artifactId>jersey-hk2</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.hk2</groupId>
<artifactId>hk2-metadata-generator</artifactId>
<version>3.0.2</version>
</dependency>
<!-- add jackson as json provider -->
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<!-- Need this to hide warning for jakarta.activation.DataSource -->
<dependency>
<groupId>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>
<version>2.0.1</version>
</dependency>
<!-- JUnit 5 -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<!-- test json data -->
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>${jsonassert.version}</version>
<scope>test</scope>
</dependency>
and MyResource.java:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.mkyong.json.service.MessageService;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
#Path("/hello")
public class MyResource {
private static final ObjectMapper mapper = new ObjectMapper();
#Inject
#Named("aws")
private MessageService awsService;
#Inject
#Named("azure")
private MessageService azureService;
#Path("/hk2/aws")
#GET
#Produces(MediaType.TEXT_PLAIN)
public String helloAws() {
String result = awsService.getHello();
ObjectNode json = mapper.createObjectNode();
return result;
}
#Path("/hk2/azure")
#GET
#Produces(MediaType.TEXT_PLAIN)
public String helloAzure() {
return azureService.getHello();
}
}
and AutoScanFeature.java :
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Feature;
import jakarta.ws.rs.core.FeatureContext;
import org.glassfish.hk2.api.DynamicConfigurationService;
import org.glassfish.hk2.api.MultiException;
import org.glassfish.hk2.api.Populator;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.hk2.utilities.ClasspathDescriptorFileFinder;
import org.glassfish.hk2.utilities.DuplicatePostProcessor;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AutoScanFeature implements Feature {
#Inject
ServiceLocator serviceLocator;
#Override
public boolean configure(FeatureContext context) {
DynamicConfigurationService dcs =
serviceLocator.getService(DynamicConfigurationService.class);
Populator populator = dcs.getPopulator();
try {
// Populator - populate HK2 service locators from inhabitants files
// ClasspathDescriptorFileFinder - find files from META-INF/hk2-locator/default
populator.populate(
new ClasspathDescriptorFileFinder(this.getClass().getClassLoader()),
new DuplicatePostProcessor());
} catch (IOException | MultiException ex) {
Logger.getLogger(AutoScanFeature.class.getName()).log(Level.SEVERE, null, ex);
}
return true;
}
}
Service interface:
#Contract
public interface UserService {
void add(User user);
}
and its implementation:
#Service
public class UserServiceImpl implements UserService {
#Override
public void add(User user) {
super.save(user, hibernateOracleTestXML);
}
}
Everything is working correctly and dependency injection is only worked by only #Service and #Contract, but I want to use #Singleton or something else for such as DAO layer.
Another hand It does not work when I use #Singleton or something else except #Service
How to solve this problem?
The #Contract and #Service are both for its default injection, according to the question, these annotations are not suitable for DAO layer, so I solved this issue by org.glassfish.hk2.utilities.binding.AbstractBinder like this:
#Override
protected void configure() {
Reflections reflections = new Reflections(packageName);
Set<Class<?>> repositories = reflections.getTypesAnnotatedWith(Repository.class, true);
repositories.stream().forEach(repo -> {
BeanAddress beanAddresses = repo.getAnnotationsByType(BeanAddress.class)[0];
try {
Class<?> requiredClass = Class.forName(beanAddresses.implPackageName());
bind(requiredClass).to(repo)
.named(Class.class.getCanonicalName()).in(Singleton.class);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
});
...
As it shows, I manually bind the interface to its class of DAO layers by an annotation that is made by myself(BeanAddress.class)

Unable to test multiple logEvent message in unit tests in Log4j2

I am having log4j2 with slf4j but getting same log message.
Provided the sample code. Getting Mutable Log Event in Argument Capture Log Event object.
Count is giving correct but same message gets repeated in when I call getAllValues() method.
Using Mockito, junit and log4j2. I debugged a lot but could find that what should be change to get correct log message in test class. I can see some other alternatives to test the same behaviour but I want to know where is the error in this piece of code.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApplicationLog {
Logger logger = LoggerFactory.getLogger(ApplicationLog.class);
public void sayHi(){
//System.out.println("hi");
logger.warn("Say Hi");
logger.warn("Say Hello");
}
}
Test class
import static org.hamcrest.CoreMatchers.is;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.LoggerContext;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.Configurator;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.*;
import org.mockito.runners.MockitoJUnitRunner;
#RunWith(MockitoJUnitRunner.class)
public class ApplicationLogTest {
private ApplicationLog applicationLog = new ApplicationLog();
#Mock
private Appender mockAppender;
#Captor
private ArgumentCaptor<LogEvent> captorLoggingEvent;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
final LoggerContext ctx = (LoggerContext) LogManager.getContext(false);
final Configuration config = ctx.getConfiguration();
Mockito.reset(mockAppender);
config.getRootLogger().addAppender(mockAppender, null, null);
Mockito.when(mockAppender.getName()).thenReturn("MockAppender");
Mockito.when(mockAppender.isStarted()).thenReturn(true);
Mockito.when(mockAppender.isStopped()).thenReturn(false);
ctx.updateLoggers();
}
#After
public void teardown() {
((LoggerContext) LogManager.getContext(false)).getConfiguration().getRootLogger().removeAppender(null);
}
#Test
public void firstTest(){
Configurator.setRootLevel(Level.TRACE);
applicationLog.sayHi();
verify(mockAppender, times(2)).append((LogEvent) captorLoggingEvent.capture());
String message = captorLoggingEvent.getAllValues().get(0).getMessage().getFormattedMessage();
**// Not getting Say Hi but getting Say Hello**
assertThat(message, is("Say Hi"));
}
}
Dependencies
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${org.log4j-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>${org.log4j-version}</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${org.log4j-version}</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>

No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call

API Requests using Postman
I tried to send HTTP requests to the java backend web server application and perform CRUD operations. GET operations are working fine and gave back the proper response but save, update and delete operations gave the following error.
Please note that there are three customer records in my database and I tried to send HTTP requests as follows;
GET http://localhost:8080/tms/api/v1/customers ---> Successful ✔
GET http://localhost:8080/tms/api/v1/customers/3 ---> Successful ✔
DELETE http://localhost:8080/tms/api/v1/customers/3 ---> Unsuccessful ❌
Error Log
Customer ID: 2
02-Feb-2022 09:59:11.271 SEVERE [http-nio-8080-exec-2] com.myapp.web.api.exceptionhandler.AppWideExceptionHandler.globalExceptionHandler null
javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call
at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:295)
at com.sun.proxy.$Proxy80.remove(Unknown Source)
at com.myapp.web.dal.CrudDAOImpl.delete(CrudDAOImpl.java:67)
at com.myapp.web.business.custom.impl.CustomerBOImpl.deleteCustomer(CustomerBOImpl.java:79)
at com.myapp.web.api.CustomerController.deleteCustomer(CustomerController.java:116)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1067)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doDelete(FrameworkServlet.java:931)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:687)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:359)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:889)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1735)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
API Layer
CustomerController.java
package com.myapp.web.api;
import com.myapp.web.api.util.ApiUtil;
import com.myapp.web.business.custom.CustomerBO;
import com.myapp.web.dto.CustomerDTO;
import com.myapp.web.exception.IdFormatException;
import com.myapp.web.exception.RecordNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#CrossOrigin(origins = "http://localhost:8080")
#RequestMapping("/api/v1/customers")
#RestController
public class CustomerController {
#Autowired
private CustomerBO customerBO;
/**
* Get all customers list.
*
* #return List<CustomerDTO> customersList.
*/
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public List<CustomerDTO> getAllCustomers() throws Exception {
return customerBO.getAllCustomers();
}
/**
* Get customer by customer ID.
*
* #return CustomerDTO customer object.
* #throws IdFormatException if the ID is not an Integer.
* #throws RecordNotFoundException if matching customer record not found,
*/
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE,
value = "/{id:\\d}")
public CustomerDTO getCustomerByID(#PathVariable(name = "id") String id) throws Exception {
System.out.println("CustomerID: " + id);
Integer customerID = ApiUtil.getIntegerId(id);
CustomerDTO customer = customerBO.getCustomerByID(customerID);
System.out.println("Customer Result: " + customer);
/* If customer not found. */
if (customer == null) throw new RecordNotFoundException();
return customer;
}
/**
* Delete customer by Customer ID.
*/
#ResponseStatus(HttpStatus.NO_CONTENT)
#DeleteMapping(value = "/{id:\\d}")
public void deleteCustomer(#PathVariable String id) throws Exception {
Integer customerID = ApiUtil.getIntegerId(id);
System.out.println("Customer ID: " + customerID);
customerBO.deleteCustomer(customerID);
}
}
Business Layer
SuperBO.java
package com.myapp.web.business;
public interface SuperBO {
}
CustomerBOImpl.java
package com.myapp.web.business.custom.impl;
import com.myapp.web.business.custom.CustomerBO;
import com.myapp.web.business.custom.util.mapper.CustomerDTOMapper;
import com.myapp.web.dal.custom.CustomerDAO;
import com.myapp.web.dto.CustomerDTO;
import com.myapp.web.entity.Customer;
import lombok.NoArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#NoArgsConstructor
#Transactional
#Service
public class CustomerBOImpl implements CustomerBO {
#Autowired
private CustomerDAO customerDAO;
#Autowired
private CustomerDTOMapper mapper;
#Override
public void deleteCustomer(int customerID) throws Exception {
/* delete. */
this.customerDAO.delete(customerID);
}
#Transactional(readOnly = true)
#Override
public CustomerDTO getCustomerByID(int customerID) throws Exception {
/* get customer by customer ID. */
return this.mapper.getCustomerDTO(this.customerDAO.get(customerID));
}
#Transactional(readOnly = true)
#Override
public List<CustomerDTO> getAllCustomers() throws Exception {
/* get all customers. */
return this.mapper.getCustomerDTOs(this.customerDAO.getAll());
}
}
CustomerDTOMapper.java
package com.myapp.web.business.custom.util.mapper;
import com.myapp.web.dto.CustomerDTO;
import com.myapp.web.entity.Customer;
import org.mapstruct.Mapper;
import java.util.List;
#Mapper(componentModel = "spring")
public abstract class CustomerDTOMapper {
/* -------------------- Customer -------------------- */
public abstract Customer getCustomer(CustomerDTO customerDTO);
public abstract CustomerDTO getCustomerDTO(Customer customer);
public abstract List<CustomerDTO> getCustomerDTOs(List<Customer> customerList);
}
Data Access Layer
SuperDAO.java
package com.myapp.web.dal;
import javax.persistence.EntityManager;
public interface SuperDAO {
EntityManager getEntityManager();
}
CrudDAO.java
package com.myapp.web.dal;
import com.myapp.web.entity.SuperEntity;
import java.io.Serializable;
import java.util.List;
public interface CrudDAO<T extends SuperEntity<Serializable>, PK extends Serializable> extends SuperDAO {
/**
* saving an entity and return the entity.
*
* #return T SuperEntity. */
T save(T entity) throws Exception;
void update(T entity) throws Exception;
void delete(PK key) throws Exception;
T get(PK key) throws Exception;
List<T> getAll() throws Exception;
}
CrudDAOImpl.java
package com.myapp.web.dal;
import com.myapp.web.entity.SuperEntity;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;
public class CrudDAOImpl<T extends SuperEntity<Serializable>, K extends Serializable> implements CrudDAO<T, K> {
private final Class<T> entityClass;
#PersistenceContext
private EntityManager entityManager;
public CrudDAOImpl() {
this.entityClass =
(Class<T>) (((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments()[0]);
}
/**
* This method is used to pass the EntityManager to the lower level classes that extend the CrudDAOImpl class.
*/
public EntityManager getEntityManager() {
return this.entityManager;
}
#Override
public void delete(K key) throws Exception {
this.entityManager.remove(key);
}
#Override
public T get(K key) throws Exception {
return this.entityManager.find(this.entityClass, key);
}
#Override
public List<T> getAll() throws Exception {
List<T> resultList = (List<T>) this.entityManager.
createQuery("SELECT e FROM " + this.entityClass.getName() + " e").getResultList();
return resultList;
}
}
CustomerDAO.java
package com.myapp.web.dal.custom;
import com.myapp.web.dal.CrudDAO;
import com.myapp.web.entity.Customer;
public interface CustomerDAO extends CrudDAO<Customer, Integer> {
}
CustomerDAOImpl.java
package com.myapp.web.dal.custom.impl;
import com.myapp.web.dal.CrudDAOImpl;
import com.myapp.web.dal.custom.CustomerDAO;
import com.myapp.web.entity.Customer;
import org.springframework.stereotype.Repository;
#Repository
public class CustomerDAOImpl extends CrudDAOImpl<Customer, Integer> implements CustomerDAO {
}
Here's what I have tried.
I tried unit testing. BO layer and DAO layer unit test case worked as intended but when I check the API by sending HTTP request using Postman, save, update and delete cannot be performed using the API.
CustomerDAOImplTest.java ----> TEST PASSED ! ✔
package com.myapp.web.dal.custom.impl;
import com.myapp.web.WebAppConfig;
import com.myapp.web.WebRootConfig;
import com.myapp.web.dal.custom.CustomerDAO;
import com.myapp.web.entity.Customer;
import com.myapp.web.entity.enumeration.GenderTypes;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import static org.junit.Assert.*;
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = {WebRootConfig.class, WebAppConfig.class})
public class CustomerDAOImplTest {
#Autowired
private CustomerDAO customerDAO;
#Test
public void checkCustomerDAO() {
assertNotNull(customerDAO);
}
#Transactional
#Test
public void getCustomerByID() throws Exception {
assertNotNull(customerDAO);
Customer customer = this.customerDAO.get(10);
System.out.println("GET Customer Entity: " + customer);
assertNotNull(customer);
}
#Test
public void getAllCustomers() throws Exception {
List<Customer> customersList = this.customerDAO.getAll();
assertEquals(2, customersList.size());
}
#Transactional
#Test
public void deleteCustomer() throws Exception {
assertNotNull(this.customerDAO);
/* delete */
this.customerDAO.delete(3);
Customer customerFromDB = this.customerDAO.get(10);
assertNull(customerFromDB);
}
}
CustomerBOImpl.java ----> TEST PASSED ! ✔
package com.myapp.web.business.custom.impl;
import com.myapp.web.WebAppConfig;
import com.myapp.web.WebRootConfig;
import com.myapp.web.business.custom.CustomerBO;
import com.myapp.web.dto.CustomerDTO;
import com.myapp.web.entity.enumeration.GenderTypes;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = {WebRootConfig.class, WebAppConfig.class})
public class CustomerBOImplTest {
#Autowired
private CustomerBO customerBO;
#Test
public void checkCustomerBO() {
assertNotNull(customerBO);
}
// #Transactional
#Test
public void deleteCustomer() throws Exception {
assertNotNull(this.customerBO);
/* delete */
this.customerBO.deleteCustomer(3);
CustomerDTO customerDTOFromDB = this.customerBO.getCustomerByID(10);
assertNull(customerDTOFromDB);
}
}
pom.xml dependencies
<dependencies>
<!-- Servlet-API -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- MySQL connector -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.27</version>
<scope>compile</scope>
</dependency>
<!-- SLF4J for logging-->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-jdk14 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>2.0.0-alpha1</version>
<scope>compile</scope>
</dependency>
<!-- Junit4 for unit testing -->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- Apache Commons Validator -->
<!-- https://mvnrepository.com/artifact/commons-validator/commons-validator -->
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
<!-- mapstruct -->
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
<scope>provided</scope>
</dependency>
<!-- Hibernate -->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.6.3.Final</version>
</dependency>
<!-- Apache Commons Codecs -->
<!-- https://mvnrepository.com/artifact/commons-codec/commons-codec -->
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
<!-- Spring Data Access ==================================================================== -->
<!--Spring ORM -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.3.14</version>
</dependency>
<!-- Apache Commons DBCP -->
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<!-- Spring Data Access - Spring AOP - Aspectj ========================================== -->
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjrt -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.9.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.7</version>
<scope>runtime</scope>
</dependency>
<!-- Spring Web MVC =================================================================== -->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.15</version>
</dependency>
<!-- JACKSON DATABIND -->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.1</version>
</dependency>
<!--Jackson Datatype-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.datatype/jackson-datatype-jsr310 -->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.13.1</version>
</dependency>
<!--Spring TestContext Framework-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.3.15</version>
<scope>test</scope>
</dependency>
</dependencies>
Development Enviroment
Java 8
Tomcat 9
I refer to these following questions and answers but, I could not fix the issue. I would appreciate some help to fix the
error and, understand the error.
https://stackoverflow.com/a/32552558/12898581
javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread
https://www.wilfriedbarth.com/til/2018-03-31-spring-transactional-annotation/

Could not autowire. No beans of 'JobRepositoryTestUtils' type found. With SpringBatchTest Annotation added

I am working on a Spring Batch unit testing using the #SpringBatchTest annotation which is supposed to automatically add the beans for JobLauncherTestUtils and JobRepositoryTestUtils.
Here's the Job configuration class:
#Configuration
#EnableBatchProcessing
public class JobConfiguration {
#Bean
public Job getJob(JobBuilderFactory jobBuilderFactory,
#Qualifier("flow_master") Flow flowMaster) {
return jobBuilderFactory.get("job")
.incrementer(new RunIdIncrementer())
.start(flowMaster)
.build().build();
}
}
Here's the Test Class:
#ExtendWith(SpringExtension.class)
#SpringBatchTest
#ContextConfiguration(classes = JobConfiguration.class)
public class SpringBatchTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Before
public void clearJobExecutions() {
this.jobRepositoryTestUtils.removeJobExecutions();
}
#Test
public void testMyJob() throws Exception {
JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters();
JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);
Assert.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
Problem:
I am getting the error messages:
Could not autowire. No beans of 'JobLauncherTestUtils' type found.
I have cloned some repo examples which are supposed to work but I am getting the same error for all of them.
Am I missing something?
You did not share your imports but you are probably mixing imports between junit4 and junit5. I'm not able to reproduce your error. Here is a complete example:
The job configuration class:
package com.example.demo;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
#Configuration
#EnableBatchProcessing
public class MyJobConfig {
#Bean
public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
return jobs.get("job")
.start(steps.get("step")
.tasklet((contribution, chunkContext) -> {
System.out.println("Hello world!");
return RepeatStatus.FINISHED;
}).build())
.build();
}
#Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.addScript("/org/springframework/batch/core/schema-h2.sql")
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(MyJobConfig.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
}
The test class:
package com.example.demo;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.test.JobLauncherTestUtils;
import org.springframework.batch.test.JobRepositoryTestUtils;
import org.springframework.batch.test.context.SpringBatchTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#SpringBatchTest
#ContextConfiguration(classes = MyJobConfig.class)
class MyJobConfigTest {
#Autowired
private JobLauncherTestUtils jobLauncherTestUtils;
#Autowired
private JobRepositoryTestUtils jobRepositoryTestUtils;
#BeforeEach
public void clearJobExecutions() {
this.jobRepositoryTestUtils.removeJobExecutions();
}
#Test
public void testMyJob() throws Exception {
// given
JobParameters jobParameters = this.jobLauncherTestUtils.getUniqueJobParameters();
// when
JobExecution jobExecution = this.jobLauncherTestUtils.launchJob(jobParameters);
// then
Assertions.assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
}
}
and the pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>so67767525</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>so67767525</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.batch</groupId>
<artifactId>spring-batch-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
<!-- While this has "boot" in the name, it does not bring any Spring Boot feature. -->
<!-- It is used to manage Spring projects dependencies that are known to work correctly together -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
The test runs successfully without the error you mentioned.

Getting Error for MockMvc perform() Methods

I am creating a Spring MVC Controller test. Compiler is showing errors for methods shown below in bold. Am I missing some library or something in my code? Any suggestions?
I am using following dependencies:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>1.3</version>
<scope>test</scope>
</dependency>
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import com.zerosolutions.view.form.LoginCredentials;
#RunWith(value=SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration("classpath:dispatcher-servlet.xml")
public class TestingFrontController {
#Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
#Before
public void setUp(){
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
}
#Test
public void getLoginSignupPage() throws Exception{
this.mockMvc.perform(**get**("/"))
.andExpect(status().isOk())
.andExpect(forwardedUrl("login"))
.andExpect(model().attribute("loginCred", **any**(LoginCredentials.class)));
}
}
add following to import these methods
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;

Categories