I'am a bit confused about Spring Data JPA repositories used in an "Annotation only" context. When starting a tomcat server on which I am deploying the application, I get the following Error:
Grave: ContainerBase.addChild: start:
org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost].StandardContext[/dashboard]]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'archivingService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.dashboard.persistence.repository.RequestsRepository com.mycompany.dashboard.core.services.archiving.ArchivingServiceImplJPA.requestsRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mycompany.dashboard.persistence.repository.RequestsRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.mycompany.dashboard.persistence.repository.RequestsRepository com.mycompany.dashboard.core.services.archiving.ArchivingServiceImplJPA.requestsRepository; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mycompany.dashboard.persistence.repository.RequestsRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.mycompany.dashboard.persistence.repository.RequestsRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
The error is clear but I can't figure out what exactly is wrong.
My first suspicion is that the rootContext is created before the persistenceCOntext, and thus my repository beans are not known when Autowiring them in the Service class.
My second suspicion is that I am missing something concerning the use of annotations.
My configuration classes:
package com.mycompany.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.mycompany.core.services.archiving.ArchivingService;
import com.mycompany.core.services.archiving.ArchivingServiceImplJPA;
import com.mycompany.core.services.restore.RestoreService;
import com.mycompany.core.services.restore.RestoreServiceImplAPI;
import com.mycompany.core.util.StatusConverter;
/**
* Configuration class used to define core(service) beans
*
*
*/
#Configuration
#ComponentScan(basePackages = { "com.mycompany.core.services", "com.mycompany.core.util"})
public class CoreConfig {
#Bean
public ArchivingService archivingService() {
return new ArchivingServiceImplJPA();
}
}
MVCConfig:
package com.mycompany.dashboard.config;
import java.util.ArrayList;
import java.util.List;
import org.dozer.DozerBeanMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.mycompany.dashboard.core.util.ApiObjectMapper;
/**
* Configuration class used to define Web beans, these beans are used for the
* REST service
*
*
*/
#Configuration
#EnableWebMvc
#ComponentScan(basePackages = { "com.mycompany.dashboard.rest.controller",
"com.mycompany.dashboard.rest.filter" })
public class MVCConfig extends WebMvcConfigurerAdapter implements
WebMvcConfigurer {
private static final String MAPPING_FILE = "META-INF/dozer/global-dto.xml";
/**
* Configures dozer mapping and objectmapper
*
* #return DozerBeanMapper
*/
#Bean
public DozerBeanMapper dozerMapper() {
final DozerBeanMapper mapper = new DozerBeanMapper();
final List<String> mappingFiles = new ArrayList<>();
mappingFiles.add(MAPPING_FILE);
mapper.setMappingFiles(mappingFiles);
return mapper;
}
#Bean
public ApiObjectMapper apiObjectMapper() {
return new ApiObjectMapper();
}
/**
* Configure Jackson Objects to JSON converter
*/
#Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(apiObjectMapper());
converters.add(converter);
}
}
PersistenceJPAConfig:
package com.mycompany.dashboard.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* Configuration class used to define persistence beans
*
*/
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories("com.mycompany.dashboard.persistence.repository")
public class PersistenceJPAConfig {
/**
* Gets LocalContainerEntityManagerFactoryBean and configures it
*
* #return LocalContainerEntityManagerFactoryBean
*/
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dataSource());
em.setPackagesToScan(new String[] { "com.mycompany.persistence.model" });
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
em.setJpaProperties(additionalProperties());
return em;
}
/**
* Configures connection to Database
*
* #return Datasource
*/
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:oracle:thin:#dbdev:1521:DEV");
dataSource.setUsername("CONTINTEGR");
dataSource.setPassword("8944CE07176988D6F30CC021471EBC9A");
return dataSource;
}
/**
* Sets PlatformTransactionManager with an EntityManager
*
* #param EntityManagerFactory
* #return PlatformTransactionManager
*/
#Bean
public PlatformTransactionManager transactionManager(
EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
Properties additionalProperties() {
Properties properties = new Properties();
// properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
// properties.setProperty("hibernate.dialect",
// "org.hibernate.dialect.MySQL5Dialect");
return properties;
}
}
WebAppInitializer:
package com.mycompany.dashboard.config;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import com.mycompany.dashboard.rest.filter.CORSFilter;
/**
* Configuration class which centralizes the core, web and persistence
* configurations
*
*/
public class WebAppInitializer implements WebApplicationInitializer {
// API servlet name
private static final String API_SERVLET_NAME = "api";
// API servlet mapping
private static final String API_SERVLET_MAPPING = "/api/*";
public void onStartup(ServletContext servletContext)
throws ServletException {
WebApplicationContext rootContext = createRootContext(servletContext);
configurePersistence(rootContext);
configureSpringMvc(servletContext, rootContext);
}
private WebApplicationContext createRootContext(
ServletContext servletContext) {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(CoreConfig.class);
rootContext.refresh();
servletContext.addListener(new ContextLoaderListener(rootContext));
servletContext.addFilter("CORSFilter", new CORSFilter())
.addMappingForUrlPatterns(null, false, "/*");
;
servletContext.setInitParameter("defaultHtmlEscape", "true");
return rootContext;
}
private void configureSpringMvc(ServletContext servletContext,
WebApplicationContext rootContext) {
AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();
mvcContext.register(MVCConfig.class);
mvcContext.setParent(rootContext);
ServletRegistration.Dynamic appServlet = servletContext.addServlet(
API_SERVLET_NAME, new DispatcherServlet(mvcContext));
appServlet.setLoadOnStartup(1);
Set<String> mappingConflicts = appServlet
.addMapping(API_SERVLET_MAPPING);
}
private void configurePersistence(WebApplicationContext rootContext) {
AnnotationConfigWebApplicationContext persistenceContext = new AnnotationConfigWebApplicationContext();
persistenceContext.register(PersistenceJPAConfig.class);
persistenceContext.setParent(rootContext);
}
}
My Service class:
package com.mycompany.dashboard.core.services.archiving;
import java.sql.Timestamp;
import java.util.LinkedList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import com.mycompany.dashboard.arcsysdashboard.core.util.StatusConverter;
import com.mycompany.dashboard.persistence.model.Request;
import com.mycompany.dashboard.persistence.repository.ArchivingsRepository;
import com.mycompany.dashboard.persistence.repository.RequestsRepository;
import com.mycompany.dashboard.rest.domain.RestRequest;
/**
* Implementing class of the archiving service interface using Spring Data JPA
* repositories
*
*/
public class ArchivingServiceImplJPA implements ArchivingService {
#Autowired
private RequestsRepository requestsRepository;
#Autowired
private ArchivingsRepository archivingsRepository;
#Autowired
private StatusConverter statusConverter;
#Override
public List<RestRequest> findLastArchivingRequests() {
List<RestRequest> recordRequests = new LinkedList<RestRequest>();
List<RestRequest> restRequests = new LinkedList<RestRequest>();
List<Request> requests = requestsRepository.findFiveLastRequests("A");
for (Request request : requests) {
RestRequest restRequest = new RestRequest(new Timestamp(request
.getDate().getTime()), this.statusConverter.getStatus(
request.getLastStatus()).toString(), archivingsRepository
.findOne(request.getLotIdent()).getCode());
restRequests.add(restRequest);
}
return recordRequests;
}
}
My repository classes:
package com.mycompany.dashboard.persistence.repository;
import java.rmi.server.UID;
import org.springframework.data.jpa.repository.JpaRepository;
import com.mycompany.dashboard.persistence.model.Record;
/**
* Spring Data Repository interface used to manage Records
*
*/
public interface ArchivingsRepository extends JpaRepository<Record, UID> {
Record findOne(Long id);
}
package com.mycompany.dashboard.persistence.repository;
import java.rmi.server.UID;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
import com.mycompany.dashboard.persistence.model.Request;
/**
* Spring Data Repository interface used to manage Requests
*/
public interface RequestsRepository extends JpaRepository<Request, UID> {
#Query("SELECT TOP 5 req FROM Request req WHERE req.owner = :name and req.type = paramType")
List<Request> findFiveLastRequestsByOwnerAndType(
#Param("owner") String author, #Param("type") String paramType);
#Query("SELECT TOP 5 req FROM Request req WHERE req.type = A")
List<Request> findFiveLastRequests(#Param("type") String paramType);
}
Place an #Import(PersistenceJPAConfig.class) to your CoreConfig class as it seems this configuration class isn't being picked up properly or at all.
Related
Question regarding our Spring Boot 2.3.8.RELEASE implementation of #Transactional. The requirement is to implement distributed transactions that writes to an instance of PostgreSQL and Artemis queues. If one commit fails, then so should the other. We are using Atomikos for our JTA Transaction Manager.
I think I have implemented everything I need, but clearly not. When I throw an Exception in my service code to test the rollback functionality, it clearly does not work: The message is written to Artemis even after I throw an exception in the service code.
Any help with diagnosing and fixing would be much appreciated. If any additional details are required, please let me know.
Please find the details of the implementation below:
Spring Boot Application:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
import org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.ConfigurableApplicationContext;
import xxx.xxx.Users;
import xxx.xxx.TransactionServiceImpl;
#SpringBootApplication
(
exclude = {
DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JmsAutoConfiguration.class,
ActiveMQAutoConfiguration.class,
ArtemisAutoConfiguration.class
}
)
public class BApplication implements CommandLineRunner
{
public static void main(String[] args) throws Exception
{
// SpringApplication.run(BoilerplateApplication.class, args);
ConfigurableApplicationContext ctx = SpringApplication.run(BApplication.class, args);
System.in.read();
ctx.close();
}
#Autowired
TransactionServiceImpl tsi;
#Override
public void run(String... args) throws Exception
{
Users user = new Users();
user.setFirstName("Moe");
user.setGender("M");
user.setLastName("Moe");
tsi.save(user);
}
}
Here is the JTA Configuration:
JTA Configuration
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.sql.DataSource;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;
import java.util.Properties;
import javax.annotation.PostConstruct;
import org.springframework.context.annotation.Bean;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.DependsOn;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import com.atomikos.icatch.config.UserTransactionService;
import com.atomikos.icatch.config.UserTransactionServiceImp;
import com.atomikos.icatch.jta.UserTransactionImp;
import com.atomikos.icatch.jta.UserTransactionManager;
import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.atomikos.jms.AtomikosConnectionFactoryBean;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.postgresql.xa.PGXADataSource;
#Configuration("jtaConfig")
public class JtaConfig
{
private static final Logger appLogger = LoggerFactory.getLogger(JtaConfig.class);
#Value("${amq.broker.url}")
private String brokerUrl;
#Value("${amq.broker.username}")
private String brokerUsername;
#Value("${amq.broker.password}")
private String brokerPassword;
#Value("${postgresql.datasource.url}")
String dataSourceUrl;
#Value("${postgresql.datasource.username}")
String dsUsername;
#Value("${postgresql.datasource.password}")
String dsPassword;
#Value("${postgresql.datasource.driver.classname}")
String dsClassName;
#Value("${postgresql.initial.connections}")
int initialDSConnections;
#Value("${postgresql.max.connections}")
int maxDSConnections;
#Bean(initMethod = "init", destroyMethod = "shutdownForce")
public UserTransactionService userTransactionService()
{
Properties atProps = new Properties();
atProps.put("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
return new UserTransactionServiceImp(atProps);
}
#Bean (initMethod = "init", destroyMethod = "close")
#DependsOn("userTransactionService")
public UserTransactionManager atomikosTransactionManager()
{
UserTransactionManager utm = new UserTransactionManager();
utm.setStartupTransactionService(false);
utm.setForceShutdown(true);
return utm;
}
#Bean
#DependsOn("userTransactionService")
public UserTransaction userTransaction()
{
UserTransactionImp ut = new UserTransactionImp();
try
{
ut.setTransactionTimeout(1000);
}
catch (SystemException _e)
{
appLogger.error("Configuration exception.", _e);
return null;
}
return ut;
}
#Bean
public Properties hibernateProperties()
{
Properties hibernateProp = new Properties();
hibernateProp.put("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
hibernateProp.put("hibernate.hbm2ddl.auto", "create-drop");
hibernateProp.put("hibernate.show_sql", true);
hibernateProp.put("hibernate.max_fetch_depth", 3);
hibernateProp.put("hibernate.jdbc.batch_size", 10);
hibernateProp.put("hibernate.jdbc.fetch_size", 50);
return hibernateProp;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter()
{
return new HibernateJpaVendorAdapter();
}
#Primary
#Bean(name = "pgDataSource1", initMethod = "init", destroyMethod = "close")
public DataSource pgDataSource1()
{
PGXADataSource primaryXaDataSource = new PGXADataSource();
primaryXaDataSource.setUrl(dataSourceUrl);
primaryXaDataSource.setUser(dsUsername);
primaryXaDataSource.setPassword(dsPassword);
AtomikosDataSourceBean xaDataSource = new AtomikosDataSourceBean();
xaDataSource.setXaDataSource(primaryXaDataSource);
xaDataSource.setUniqueResourceName("primaryXaDs1");
xaDataSource.setMinPoolSize(initialDSConnections);
xaDataSource.setMaxPoolSize(maxDSConnections);
return xaDataSource;
}
#Primary
#Bean(name = "jmsConnectionFactory", initMethod = "init", destroyMethod = "close")
public ConnectionFactory connectionFactory()
{
AtomikosConnectionFactoryBean atomikosConnectionFactoryBean = new AtomikosConnectionFactoryBean();
ActiveMQConnectionFactory activeMqXaConnectionFactory = new ActiveMQConnectionFactory();
try
{
activeMqXaConnectionFactory.setBrokerURL(brokerUrl);
activeMqXaConnectionFactory.setUser(brokerUsername);
activeMqXaConnectionFactory.setPassword(brokerPassword);
atomikosConnectionFactoryBean.setUniqueResourceName("jmsXAConnectionFactory");
atomikosConnectionFactoryBean.setLocalTransactionMode(false);
atomikosConnectionFactoryBean.setXaConnectionFactory(activeMqXaConnectionFactory);
}
catch (JMSException _e)
{
appLogger.info("JMS Configuration Error: " + _e);
_e.printStackTrace();
}
return atomikosConnectionFactoryBean;
}
#PostConstruct
public void postConstructDetails()
{
appLogger.info("Post Construct Start: JtaConfig.");
appLogger.info(" - JMS: Artemis URL: {}", brokerUrl);
appLogger.info(" - Artemis Username: {}", brokerUsername);
appLogger.info(" - Artemis Password: {}", brokerPassword);
appLogger.info(" - DS: PostgreSQL URL: {}", dataSourceUrl);
appLogger.info(" - DS: PostgreSQL Username: {}", dsUsername);
appLogger.info(" - DS: PostgreSQL Password: {}", dsPassword);
appLogger.info(" - DS: PostgreSQL Min Conn: {}", initialDSConnections);
appLogger.info(" - DS: PostgreSQL Max Conn: {}", maxDSConnections);
appLogger.info("Post Construct End: JtaConfig.");
appLogger.info(" ");
}
}
Here is the implementation for Services Configuration:
Services Configuration:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.jta.JtaTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = "xxx.xxx.service")
public class ServicesConfig
{
private Logger appLogger = LoggerFactory.getLogger(ServicesConfig.class);
#Autowired
JtaConfig jtaConfig;
#Bean(name = "xaJmsTemplate")
public JmsTemplate jmsTemplate()
{
JmsTemplate jmsTemplate = new JmsTemplate();
jmsTemplate.setConnectionFactory(jtaConfig.connectionFactory());
jmsTemplate.setPubSubDomain(false);
return jmsTemplate;
}
#Bean(name = "entityManangerFactory")
public EntityManagerFactory entityManagerFactory()
{
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPackagesToScan("xxx.xxx.model");
factoryBean.setDataSource(jtaConfig.pgDataSource1());
factoryBean.setJpaProperties(jtaConfig.hibernateProperties());
factoryBean.setPersistenceUnitName("entityManagerFactoryA");
factoryBean.setJpaVendorAdapter(jtaConfig.jpaVendorAdapter());
factoryBean.afterPropertiesSet();
return factoryBean.getNativeEntityManagerFactory();
}
#Bean(name = "transactionManager")
public PlatformTransactionManager transactionManager()
{
JtaTransactionManager ptm = new JtaTransactionManager();
ptm.setTransactionManager(jtaConfig.atomikosTransactionManager());
ptm.setUserTransaction(jtaConfig.userTransaction());
return ptm;
}
#PostConstruct
public void postConstructDetails()
{
appLogger.info("Post Construct Start: ServicesConfig.");
appLogger.info(" - JMS: Artemis URL: {}", jtaConfig);
appLogger.info(" - JMS Template: {}", jmsTemplate());
appLogger.info("Post Construct End: ServicesConfig.");
appLogger.info(" ");
}
}
Here is the Service implementation:
TransactionServiceImpl
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xxx.xxx.Users;
#Service("transactionService")
#Transactional
public class TransactionServiceImpl implements TransactionServiceIntf
{
private static final Logger appLogger = LoggerFactory.getLogger(TransactionServiceImpl.class);
#Autowired
#Qualifier("xaJmsTemplate")
JmsTemplate jmsTemplate;
#Override
public Users save(Users _user)
{
appLogger.info("TransactionServiceImpl: save: Entered.");
Users user = _user;
try
{
if(user == null)
{
appLogger.info("User: Null.");
}
else
{
if(jmsTemplate == null)
{
appLogger.info("JMS Template: Null.");
}
else
{
appLogger.info("JMS Template: Saving.");
jmsTemplate.convertAndSend("crequests", user);
}
}
// The rollback should happen with the exception.
throw new Exception();
}
catch(Exception _e)
{
appLogger.error("Catching exception: " + _e);
}
appLogger.info("TransactionServiceImpl: save: Exiting.");
return user;
}
}
I get this exception with this Configuration class
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableTransactionManagement//enable tx management
#EnableWebMvc//enables webmvc
//load properties into spring container
#PropertySource("classpath:app.properties")
//all layered classes common package name
#ComponentScan("in.nit")
public class AppConfig {
#Autowired
private Environment env;
//1) DataSource
#Bean
public DataSource ds() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName(env.getProperty("db.driver"));
ds.setUrl(env.getProperty("db.url"));
ds.setUsername(env.getProperty("db.user"));
ds.setPassword(env.getProperty("db.pwd"));
return ds;
}
//2)SessionFactory
#Bean
public SessionFactory sf() {
LocalSessionFactoryBean sf = new LocalSessionFactoryBean();
sf.setDataSource(ds());
sf.setHibernateProperties(props());
sf.setPackagesToScan("in.nit.model");
return sf.getObject();
}
//3)HibernateProperties
public Properties props() {
Properties p = new Properties();
p.put("hibernate.dialect", env.getProperty("orm.dialect"));
p.put("hibernate.show_sql", env.getProperty("orm.showsql"));
p.put("hibernate.format_sql",env.getProperty("orm.fmtsql"));
p.put("hibernate.hbm2ddl.auto", env.getProperty("orm.hbm2ddl.auto"));
return p;
}
//4)HibernateTemplate
#Bean
public HibernateTemplate ht() {
HibernateTemplate ht = new HibernateTemplate();
ht.setSessionFactory(sf());
return ht;
}
//5)HibernateTx Manager
#Bean
public HibernateTransactionManager htx() {
HibernateTransactionManager htx = new HibernateTransactionManager();
htx.setSessionFactory(sf());
return htx;
}
//6)ViewResolver
#Bean
public InternalResourceViewResolver ivr() {
InternalResourceViewResolver ivr = new InternalResourceViewResolver();
ivr.setPrefix(env.getProperty("mvc.prefix"));
ivr.setSuffix(env.getProperty("mvc.suffix"));
return ivr;
}
}
and I get the exception
Error creating bean with name 'ht' defined in in.nit.config.AppConfig: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sessionFactory' is required
obviously it has something to do with session factory
But when i replace the config with the code below it works fine
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;
import org.springframework.orm.hibernate5.HibernateTemplate;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#Configuration
#EnableTransactionManagement //enables HtX
#EnableWebMvc // Spring MVC Activated
//load properties into Spring container
#PropertySource("classpath:app.properties")
//all layered classes common package name
#ComponentScan("in.nit")
public class AppConfig2 {
#Autowired
private Environment env;
//1. DataSource
#Bean
public DataSource ds() {
BasicDataSource d=new BasicDataSource();
d.setDriverClassName(env.getProperty("db.driver"));
d.setUrl(env.getProperty("db.url"));
d.setUsername(env.getProperty("db.user"));
d.setPassword(env.getProperty("db.pwd"));
return d;
}
//2. SessionFactrory
#Bean
public LocalSessionFactoryBean sf() {
LocalSessionFactoryBean s=new LocalSessionFactoryBean();
s.setDataSource(ds());
s.setHibernateProperties(props());
//s.setAnnotatedClasses(ShipmentType.class);
s.setPackagesToScan("in.nit.model");
return s;
}
#Bean
public Properties props() {
Properties p=new Properties();
p.put("hibernate.dialect", env.getProperty("orm.dialect"));
p.put("hibernate.show_sql", env.getProperty("orm.showsql"));
p.put("hibernate.format_sql", env.getProperty("orm.fmtsql"));
p.put("hibernate.hbm2ddl.auto", env.getProperty("orm.hbm2ddl.auto"));
return p;
}
//3. HT
#Bean
public HibernateTemplate ht() {
HibernateTemplate h=new HibernateTemplate();
h.setSessionFactory(sf().getObject());
return h;
}
//4. HtxM
#Bean
public HibernateTransactionManager htx() {
HibernateTransactionManager htm=new HibernateTransactionManager();
htm.setSessionFactory(sf().getObject());
return htm;
}
//5. ViewResovler
#Bean
public InternalResourceViewResolver ivr() {
InternalResourceViewResolver v=new InternalResourceViewResolver();
v.setPrefix(env.getProperty("mvc.prefix"));
v.setSuffix(env.getProperty("mvc.suffix"));
return v;
}
}
Can anyone explain why is the exception is being thrown in the first case ?
And both classes AppConfig and AppCOnfig2 seem to be doing the same thing.
Can anyone point what out specifically where and which lines make a difference?
Definition : LocalSessionFactoryBean is the FactoryBean that creates a Hibernate SessionFactory. It provides the SessionFactory object and itself is not a SessionFactory. In case you are getting exception, you are not passing the sessionfactory object and instead passing factoryBean which causes illegalArgumentException.
Original documentation: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/LocalSessionFactoryBean.html
I recently added CORS configuration in my springboot app. Below is the code for this configuration.
package com.turtlemint.verticals.commonverticals;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.WebFluxConfigurer;
/**
* #author praveenkamath
**/
#Configuration
#EnableWebFlux
public class CorsConfiguration implements WebFluxConfigurer {
#Value("${cors.allowed.origins}")
private String[] corsSites;
#Value("${cors.enabled}")
private boolean isCorsEnabled;
#Override
public void addCorsMappings(final CorsRegistry registry) {
if(isCorsEnabled) {
registry.addMapping("/api/device/**").allowedOrigins(corsSites).allowedMethods("*");
registry.addMapping("/api/sehat/**").allowedOrigins(corsSites).allowedMethods("*");
registry.addMapping("/api/dukandaar/**").allowedOrigins(corsSites).allowedMethods("*");
return;
} registry.addMapping("/**");
}
}
My application.properties
### CORS ###
cors.enabled=true
cors.allowed.origins=*
### CORS ###
After adding it, I ran into 2 issues:
A PUT request with nested JSON gives below error
Internal Server Error","message":"Type definition error: [simple type, class com.turtlemint.verticals.commonverticals.common.containers.v1.collections.ReviewPayment]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.turtlemint.verticals.commonverticals.common.containers.v1.collections.ReviewPayment` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)\n at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: com.turtlemint.verticals.commonverticals.dukandaar.containers.dto.DukandaarCheckoutDTO[\"reviewPayment\"])
ReviewPayment Java class:
package com.turtlemint.verticals.commonverticals.common.containers.v1.collections;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.turtlemint.verticals.commonverticals.common.enums.v1.ReviewPaymentStatusEnum;
import lombok.Data;
#Data
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(JsonInclude.Include.NON_NULL)
public class ReviewPayment {
private ReviewPaymentStatusEnum status;
private String rejectionReason;
public ReviewPayment(ReviewPaymentStatusEnum status, String rejectionReason) {
this.status = status;
this.rejectionReason = rejectionReason;
}
}
I added a default constructor in above class and it worked.
Getting below error when redirecting to a view from backend
{
"timestamp": 1576568268085,
"path": "/api/dukandaar/v1/payment/callback/HDFC",
"status": 500,
"error": "Internal Server Error",
"message": "Could not resolve view with name 'get_redirect'."
}
My controller:
package com.turtlemint.verticals.commonverticals.common.controllers.v1;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.turtle.enums.VerticalEnum;
import com.turtlemint.verticals.commonverticals.common.constants.v1.Constants;
import com.turtlemint.verticals.commonverticals.common.constants.v1.ThymeConstants;
import com.turtlemint.verticals.commonverticals.common.containers.v1.mappers.PaymentCallbackDTO;
import com.turtlemint.verticals.commonverticals.common.containers.v1.mappers.PaymentRedirectRequestDTO;
import com.turtlemint.verticals.commonverticals.common.containers.v1.mappers.ReviewStatusUpdateRequestDTO;
import com.turtlemint.verticals.commonverticals.common.containers.v1.mappers.ReviewStatusUpdateResponseDTO;
import com.turtlemint.verticals.commonverticals.common.containers.v1.mappers.notification.share.ShareRequestMapper;
import com.turtlemint.verticals.commonverticals.common.enums.v1.ReviewPaymentStatusEnum;
import com.turtlemint.verticals.commonverticals.common.services.CommonServiceFactory;
import com.turtlemint.verticals.commonverticals.common.utils.v1.BrokerUtils;
import com.turtlemint.verticals.commonverticals.common.utils.v1.MapUtils;
import com.turtlemint.verticals.commonverticals.deviceprotection.services.v1.DeviceProtectionServiceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;
import java.util.HashMap;
import java.util.Map;
/**
* #author praveenkamath
**/
#Controller
#RequestMapping("/api/{apiVertical}")
public class PaymentController {
private static final Logger LOG = LoggerFactory.getLogger(PaymentController.class);
private static final String REDIRECTION_PARAMS = "redirectionParams";
#Autowired
private CommonServiceFactory commonServiceFactory;
#Autowired
private DeviceProtectionServiceFactory deviceProtectionServiceFactory;
#GetMapping(value = "/v1/payment/callback/{insurer}")
public String processPayment(#PathVariable final String insurer, #PathVariable final String apiVertical, final Model model, final ServerHttpRequest serverRequest){
LOG.info("[processPayment] request received {} for insurer {}",serverRequest.getQueryParams(), insurer);
Map<String,Object> requestMap= MapUtils.convertMultiToRegularMap(serverRequest.getQueryParams());
VerticalEnum verticalEnum = VerticalEnum.getValue(apiVertical);
final String url = commonServiceFactory.getCheckoutService().processPayment(BrokerUtils.determineBroker(serverRequest.getURI().getHost()), requestMap, verticalEnum, insurer);
final Map<String, String> redirectionParams = new HashMap<>();
redirectionParams.put("url", url);
model.addAttribute(REDIRECTION_PARAMS, redirectionParams);
return ThymeConstants.REDIRECT_GET_TEMPLATE;
}
}
public class ThymeConstants {
private ThymeConstants() {}
public static final String REDIRECT_GET_TEMPLATE = "get_redirect";
}
My GET request:
https://<DOMAIN>/api/dukandaar/v1/payment/callback/HDFC?<query_params>
I comment out the CORS configuration and everything works fine.
I am still pulling my hair trying to find out the 2nd issue. Some help would be appreciated.
Finally found the solution for the 2nd issue. Had to override the thymeleaf configuration.
CorsConfiguration now looks like this:
package com.turtlemint.verticals.commonverticals.common.security.cors;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.reactive.config.CorsRegistry;
import org.springframework.web.reactive.config.EnableWebFlux;
import org.springframework.web.reactive.config.ViewResolverRegistry;
import org.springframework.web.reactive.config.WebFluxConfigurer;
import org.thymeleaf.spring5.ISpringWebFluxTemplateEngine;
import org.thymeleaf.spring5.SpringWebFluxTemplateEngine;
import org.thymeleaf.spring5.templateresolver.SpringResourceTemplateResolver;
import org.thymeleaf.spring5.view.reactive.ThymeleafReactiveViewResolver;
import org.thymeleaf.templatemode.TemplateMode;
/**
* #author praveenkamath
**/
#Configuration
#EnableWebFlux
public class CorsConfiguration implements ApplicationContextAware, WebFluxConfigurer {
#Value("${cors.allowed.origins}")
private String[] corsSites;
#Value("${cors.enabled}")
private boolean isCorsEnabled;
private ApplicationContext ctx;
#Override
public void setApplicationContext(ApplicationContext context) {
this.ctx = context;
}
#Override
public void addCorsMappings(final CorsRegistry registry) {
if(isCorsEnabled) {
registry.addMapping("/api/device/**").allowedOrigins(corsSites).allowedMethods("PUT", "PATCH", "DELETE", "OPTIONS");
registry.addMapping("/api/sehat/**").allowedOrigins(corsSites).allowedMethods("PUT", "PATCH", "DELETE", "OPTIONS");
registry.addMapping("/api/dukandaar/**").allowedOrigins(corsSites).allowedMethods("PUT", "PATCH", "DELETE", "OPTIONS");
return;
} registry.addMapping("/**");
}
#Bean
SpringResourceTemplateResolver thymeleafTemplateResolver() {
final SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(this.ctx);
resolver.setPrefix("classpath:/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCacheable(false);
resolver.setCheckExistence(false);
return resolver;
}
#Bean
ISpringWebFluxTemplateEngine thymeleafTemplateEngine() {
final SpringWebFluxTemplateEngine templateEngine = new SpringWebFluxTemplateEngine();
templateEngine.setTemplateResolver(thymeleafTemplateResolver());
return templateEngine;
}
#Bean
ThymeleafReactiveViewResolver thymeleafChunkedAndDataDrivenViewResolver() {
final ThymeleafReactiveViewResolver viewResolver = new ThymeleafReactiveViewResolver();
viewResolver.setTemplateEngine(thymeleafTemplateEngine());
viewResolver.setResponseMaxChunkSizeBytes(8192); // OUTPUT BUFFER size limit
return viewResolver;
}
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.viewResolver(thymeleafChunkedAndDataDrivenViewResolver());
}
}
I have a Spring MVC project using Hibernate ORM. When I try to make integration test with TestNG I get java.lang.IllegalStateException: Failed to load ApplicationContext. Here is my stack trace:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.transaction.TestContextTransactionUtils.retrieveTransactionManager(TestContextTransactionUtils.java:163)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.getTransactionManager(TransactionalTestExecutionListener.java:361)
...
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class [kz.agrotrade.hibernate.HibernateTestConfig]; nested exception is java.io.FileNotFoundException: class path resource [org/springframework/context/annotation/AutoProxyRegistrar.class] cannot be opened because it does not exist
at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:546)
...
Caused by: java.io.FileNotFoundException: class path resource [org/springframework/context/annotation/AutoProxyRegistrar.class] cannot be opened because it does not exist
at org.springframework.core.io.ClassPathResource.getInputStream(ClassPathResource.java:172)
...
Project structure:
Exception occurs when I'm trying to execute this test class:
package kz.agrotrade.hibernate;
import kz.agrotrade.domain.User;
import kz.agrotrade.testutil.Common;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSet;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.springframework.beans.factory.annotation.Autowired;
import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
public class HibernateUserRepositoryTest extends HibernateRepositoryTest {
#Autowired
HibernateUserRepository userRepository;
#Spy
private User superman;
#BeforeClass
public void setUp() {
MockitoAnnotations.initMocks(this);
superman = Common.getSuperman();
}
#Override
protected IDataSet getDataSet() throws Exception {
IDataSet dataSet = new FlatXmlDataSet(
this.getClass().getClassLoader().getResourceAsStream("Users.xml"));
return dataSet;
}
#Test
public void findByLogin() {
User user = userRepository.findByLogin("kent777");
Assert.assertNotNull(user);
Assert.assertEquals(user, superman);
}
}
HibernateRepositoryTest.java:
package kz.agrotrade.hibernate;
import org.dbunit.database.DatabaseDataSourceConnection;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.operation.DatabaseOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests;
import org.testng.annotations.BeforeMethod;
import javax.sql.DataSource;
#ContextConfiguration(classes = {HibernateTestConfig.class})
public abstract class HibernateRepositoryTest extends AbstractTransactionalTestNGSpringContextTests {
#Autowired
DataSource dataSource;
#BeforeMethod
public void setUp() throws Exception {
IDatabaseConnection dbConn = new DatabaseDataSourceConnection(dataSource);
DatabaseOperation.CLEAN_INSERT.execute(dbConn, getDataSet());
}
protected abstract IDataSet getDataSet() throws Exception;
}
HibernateTestConfig.java
package kz.agrotrade.hibernate;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
#EnableTransactionManagement
#ComponentScan("kz.agrotrade")
public class HibernateTestConfig {
#Autowired
private Environment environment;
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan("kz.agrotrade");
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("org.postgresql.Driver");
dataSource.setUrl("jdbc:postgresql://localhost:5432/agro-core");
dataSource.setUsername("agro");
dataSource.setPassword("agropass");
return dataSource;
}
private Properties hibernateProperties() {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect");
properties.setProperty("hibernate.hbm2ddl.auto", "create-drop");
properties.setProperty("hibernate.show_sql", "true");
properties.setProperty("hibernate.format_sql", "true");
return properties;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(SessionFactory s) {
HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(s);
return txManager;
}
}
I am not exactly sure whats causing the issue. How can I resolve this error?
As mr. Julien Herr advised, I ran my test with maven only and encountered with the A ServletContext is required to configure default servlet handling error. So the solution is to add #WebAppConfiguration to the test class:
#WebAppConfiguration
#ContextConfiguration(classes = {HibernateTestConfig.class})
public abstract class HibernateRepositoryTest extends AbstractTransactionalTestNGSpringContextTests {
#Autowired
DataSource dataSource;
#BeforeMethod
public void setUp() throws Exception {
IDatabaseConnection dbConn = new DatabaseDataSourceConnection(dataSource);
DatabaseOperation.CLEAN_INSERT.execute(dbConn, getDataSet());
}
protected abstract IDataSet getDataSet() throws Exception;
}
I am working from the Spring data tutorial here: http://spring.io/guides/tutorials/data/3/
I am trying to get my Spring 4 + Hibernate app up and running. I have created the following unit test according to the guide:
/**
*
*/
package com.corrisoft.air.db.integration;
import static org.junit.Assert.*;
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.transaction.TransactionConfiguration;
import org.springframework.transaction.annotation.Transactional;
import com.corrisoft.air.db.JPAConfiguration;
import com.corrisoft.air.db.repository.PersonsRepository;
import com.corrisoft.air.model.Person;
/**
* #author Corrisoft Android Development
*
*/
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {JPAConfiguration.class})
#Transactional
#TransactionConfiguration(defaultRollback = true)
public class PersonsRepositoryIntegerationTests {
#Autowired
PersonsRepository personsRepository;
#Test
public void thatItemIsInsertedIntoRepoWorks() throws Exception {
int id = 42;
Person person = new Person();
person.setId(id);
person.setFirstName("Zaphod");
person.setLastName("Beeblebrox");
personsRepository.save(person);
Person retrievedPerson = personsRepository.findById(id);
assertNotNull(retrievedPerson);
assertEquals(id, retrievedPerson.getId());
}
}
This tests the repository that I've created here:
/**
*
*/
package com.corrisoft.air.db.repository;
import com.corrisoft.air.model.Person;
import org.springframework.data.repository.CrudRepository;
/**
* #author Corrisoft Android Development
*
*/
public interface PersonsRepository extends CrudRepository<Person, Integer>{
Person findById(long id);
}
And I'm getting the following exception:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [com.corrisoft.air.db.repository.PersonsRepository] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1100)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:855)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480)
... 28 more
The docs say that a proxy object will be created from the interface if I have the JPAConfuration class like this:
/**
*
*/
package com.corrisoft.air.db;
import java.sql.SQLException;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.orm.hibernate4.HibernateExceptionTranslator;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.corrisoft.air.db.repository.PersonsRepository;
/**
* #author Corrisoft Android Development
*
*/
#Configuration
#EnableJpaRepositories(basePackages = "com.corrisoft.db.repository",
includeFilters = #ComponentScan.Filter(value = { PersonsRepository.class }, type = FilterType.ASSIGNABLE_TYPE))
#EnableTransactionManagement
public class JPAConfiguration {
#Bean
public DataSource dataSource() throws SQLException {
EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
return builder.setType(EmbeddedDatabaseType.H2).build();
}
#Bean
public EntityManagerFactory entityManagerFactory() throws SQLException {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.corrisoft.air.model");
factory.setDataSource(dataSource());
factory.afterPropertiesSet();
return factory.getObject();
}
#Bean
public EntityManager entityManager(EntityManagerFactory entityManagerFactory) {
return entityManagerFactory.createEntityManager();
}
#Bean
public PlatformTransactionManager transactionManager() throws SQLException {
JpaTransactionManager txManager = new JpaTransactionManager();
txManager.setEntityManagerFactory(entityManagerFactory());
return txManager;
}
#Bean
public HibernateExceptionTranslator hibernateExceptionTranslator() {
return new HibernateExceptionTranslator();
}
}
I've already found several issues with the tutorial and am thinking this is another.
You are scanning wrong package for repositories:
... basePackages = "com.corrisoft.db.repository" ...
whereas the correct one is
import com.corrisoft.air.db.repository.PersonsRepository;