Spring MVC Rest API - No qualifying bean of type 'com.app.dao.AdminsRepository' - spring

This is my first experience using Spring MVC with REST API for having an angular front end. I created 3 configuration files:
Here is my ApplicationConfig
package com.app.config;
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.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
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.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import javax.persistence.EntityManagerFactory;
#SuppressWarnings("unused")
#EnableWebMvc
#Configuration
#ComponentScan("com.app.controller")
#EnableJpaRepositories("com.app.dao")
public class ApplicationConfig {
#Bean
public InternalResourceViewResolver setup() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
#Bean
public DataSource dataSource() {
System.out.println("in datasoure");
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/db");
dataSource.setUsername("root");
dataSource.setPassword("");
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setGenerateDdl(true);
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setJpaVendorAdapter(vendorAdapter);
factory.setPackagesToScan("com.app.model");
factory.setDataSource(dataSource());
return factory;
}
#Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory emf) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(emf);
return transactionManager;
}
}
MVC Config
package com.app.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
#EnableWebMvc
#Configuration
public class MvcConfig implements WebMvcConfigurer {
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/views/", ".jsp");
}
#Bean
public InternalResourceViewResolver setup() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
WebInitializer
package com.app.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
#Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
#Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { ApplicationConfig.class, MvcConfig.class };
}
#Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
I also created a controller :
package com.app.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.app.dao.AdminsRepository;
import com.app.model.Admin;
#SuppressWarnings("unused")
#Controller
public class AdminsController {
#Autowired
private AdminsRepository adminsRepository;
#GetMapping("/admins")
#ResponseBody
public String getAllAdmins(Model model) {
return adminsRepository.findAll().toString();
}
#GetMapping("/admin/{id}")
#ResponseBody
public String getAdmin(#PathVariable("id") int id, Model model) {
return adminsRepository.findById((long) id).orElse(null).toString();
}
#PostMapping("/admin")
#ResponseBody
public String createAdmin(Admin admin, Model model) {
System.out.println(admin);
return adminsRepository.save(admin).toString();
}
}
The repository :
package com.app.dao;
//import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.app.model.Admin;
#Repository
public interface AdminsRepository extends JpaRepository <Admin, Long>{ }
And my model :
package com.app.model;
import java.io.Serializable;
import javax.persistence.*;
import java.sql.Timestamp;
import java.util.List;
#Entity
#Table(name="admins")
#NamedQuery(name="Admin.findAll", query="SELECT a FROM Admin a")
public class Admin implements Serializable {
private static final long serialVersionUID = 1L;
#Id
private int id;
#Column(name="created_at")
private Timestamp createdAt;
private String email;
private String login;
private String password;
private String name;
private String surname;
// ... getters and setters + delegated methods
}
When I start running the application and open the browser I receive an error message:
No qualifying bean of type 'com.app.dao.AdminsRepository' available:
expected at least 1 bean which qualifies as autowire candidate. Dependency annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}

G'day David,
Just breaking down the answer moiljter already gave you.
You can only #Autowire objects that are declared in packages being scanned for components.
Currently, your #ComponentScan annotation only includes your controller package:
#ComponentScan("com.app.controller")
Broaden the search slightly like so:
#ComponentScan("com.app")
Then it should pick up your AdminsRepository and hum nicely.
Cheers,
ALS

You need to add "com.app.dao" to the list of packages that Spring will scan for components (and maybe also "com.app.model" if any of those annotations are Spring ones), or just change it to scan "com.app" (which will include everything in your app.

Related

How to use two data source for same entity in spring boot application running on tomcat

I have one micro-service named order-service in spring boot.
:: Spring Boot :: (v2.0.5.RELEASE)
in that micro-service, in service layer I have 2 service class 1. OrderManagerService and OrderService. From OrderService I call Repository Interface IOrderRequestRepository which extends PagingAndSortingRepository interface. so The call is basically OrderManagerService -> OrderService -> IOrderRequestRepository.
Right now I am using one data source for the micro-service. Now my requirement is I have to use 2 data source because in OrderManagerService there is one method getCustomerVisitsForMonth(Long customerID) which frequently used and we don't want to give load on prod DB server. Instead we will use prod-replica server for this one particular method.
I have googled a lot of blogs and tried to implement but ending up getting different exception.
below are exceptions:
could not execute query; SQL [SELECT * FROM ....(this is the actual query)]; nested exception is org.hibernate.exception.SQLGrammarException: could not execute query",
Could not open JPA EntityManager for transaction; nested exception is org.hibernate.TransactionException: JDBC begin transaction failed:
Below are my sample code:
application-env.properties
spring.datasource.url=jdbc:mysql://someurl:3306/orders?zeroDateTimeBehavior=convertToNull&useSSL=false
spring.datasource.username=<username>
spring.datasource.password=<password>
spring.datasource.driverClassName=com.mysql.jdbc.Driver
#replica datasource details
spring.replica.datasource.url=jdbc:mysql://someurl:3306/order?zeroDateTimeBehavior=convertToNull&useSSL=false
spring.replica.datasource.username=<username>
spring.replica.datasource.password=<password>
spring.replica.datasource.driverClassName=com.mysql.jdbc.Driver
spring.datasource.tomcat.initial-size=15
spring.datasource.tomcat.max-wait=20000
spring.datasource.tomcat.max-active=5
spring.datasource.tomcat.max-idle=4
spring.datasource.tomcat.min-idle=2
spring.datasource.tomcat.default-auto-commit=true
#replica data source details
spring.replica.datasource.tomcat.initial-size=15
spring.replica.datasource.tomcat.max-wait=20000
spring.replica.datasource.tomcat.max-active=5
spring.replica.datasource.tomcat.max-idle=4
spring.replica.datasource.tomcat.min-idle=2
spring.replica.datasource.tomcat.default-auto-commit=true
Main class
package in.demo.order.web.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#SpringBootApplication(scanBasePackages = "in.demo.order",
exclude = { SecurityAutoConfiguration.class })
public class OrderServiceApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(OrderServiceApplication.class);
}
}
I have created 2 different packages for Repository classes and for Entity classes, however my Entity and Repository are same.
packages
in.demo.order.dao
in.demo.order.repodao
Configuration classes
MainDataSourceConfiguration
package in.demo.order.web.config;
import in.demo.order.replicadao.IOrderRequestRepositoryForReplica;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.*;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
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 javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "in.demo.order.dao",
entityManagerFactoryRef = "mainEntityManagerFactory",
transactionManagerRef = "mainTransactionManager"
)
public class MainDataSourceConfiguration {
#Autowired
private Environment environment;
#Primary
#Bean(name = "mainDataSourceProperties")
#ConfigurationProperties("spring.datasource")
public DataSourceProperties mainDataSourceProperties() {
return new DataSourceProperties();
}
#Primary
#Bean(name = "mainDataSource")
#ConfigurationProperties("spring.datasource.configuration")
public DataSource mainDataSource(
#Qualifier("mainDataSourceProperties") DataSourceProperties mainDataSourceProperties) {
return mainDataSourceProperties
.initializeDataSourceBuilder()
.type(org.apache.tomcat.jdbc.pool.DataSource.class)
.build();
}
#Primary
#Bean(name = "mainEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean mainEntityManagerFactory(
EntityManagerFactoryBuilder mainEntityManagerFactoryBuilder,
#Qualifier("mainDataSource") DataSource mainDataSource) {
Map<String, String> mainJpaProperties = new HashMap<>();
mainJpaProperties.put("hibernate.dialect",
environment.getProperty("spring.jpa.properties.hibernate.dialect"));
mainJpaProperties.put("hibernate.hbm2ddl.auto",
environment.getProperty("spring.jpa.hibernate.ddl-auto"));
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = mainEntityManagerFactoryBuilder
.dataSource(mainDataSource)
.packages("in.demo.order.dao.model")
.persistenceUnit("mainDataSource")
.properties(mainJpaProperties)
.build();
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
#Primary
#Bean(name = "mainTransactionManager")
public PlatformTransactionManager mainTransactionManager(
#Qualifier("mainEntityManagerFactory") EntityManagerFactory mainEntityManagerFactory) {
return new JpaTransactionManager(mainEntityManagerFactory);
}
}
ReplicaDataSourceConfiguration
package in.demo.order.web.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
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 javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "in.demo.order.replicadao",
entityManagerFactoryRef = "replicaEntityManagerFactory",
transactionManagerRef = "replicaTransactionManager"
)
public class ReplicaDataSourceConfiguration {
#Autowired
private Environment environment;
#Bean(name = "replicaDataSourceProperties")
#ConfigurationProperties("spring.replica.datasource")
public DataSourceProperties replicaDataSourceProperties() {
return new DataSourceProperties();
}
#Bean(name = "replicaDataSource")
#ConfigurationProperties("spring.replica.datasource.configuration")
public DataSource replicaDataSource(
#Qualifier("replicaDataSourceProperties") DataSourceProperties replicaDataSourceProperties) {
return replicaDataSourceProperties
.initializeDataSourceBuilder()
.type(org.apache.tomcat.jdbc.pool.DataSource.class)
.build();
}
#Bean(name = "replicaEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean replicaEntityManagerFactory(
EntityManagerFactoryBuilder replicaEntityManagerFactoryBuilder,
#Qualifier("replicaDataSource") DataSource replicaDataSource) {
Map<String, String> replicaJpaProperties = new HashMap<>();
replicaJpaProperties.put("hibernate.dialect",
environment.getProperty("spring.jpa.properties.hibernate.dialect"));
replicaJpaProperties.put("hibernate.hbm2ddl.auto",
environment.getProperty("spring.jpa.hibernate.ddl-auto"));
LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean = replicaEntityManagerFactoryBuilder
.dataSource(replicaDataSource)
.packages("in.demo.order.replicadao.model")
.persistenceUnit("replicaDataSource")
.properties(replicaJpaProperties)
.build();
localContainerEntityManagerFactoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
return localContainerEntityManagerFactoryBean;
}
#Bean(name = "replicaTransactionManager")
public PlatformTransactionManager replicaTransactionManager(
#Qualifier("replicaEntityManagerFactory") EntityManagerFactory replicaEntityManagerFactory) {
return new JpaTransactionManager(replicaEntityManagerFactory);
}
}
OrderManagerService
package in.demo.order.service;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
#Transactional
public class OrderManagerService{
#Autowired
private OrderService orderService;
public CustomerVisitsResponse getCustomerVisitsForMonthForReplicaDataSource(Long customerId) {
return orderService.getTotalCustomerVisitsForMonth(customerId);
}
public CustomerVisitsResponse getCustomerVisitsForMonthForMainDataSource(Long customerId) {
return orderService.getTotalCustomerVisitsForMonthForMainDataSource(customerId);
}
}
OrderService
package in.demo.order.service;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import in.demo.order.replicadao.IOrderRequestRepositoryForReplica;
import in.demo.order.dao.IOrderRequestRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
#Transactional(rollbackFor = Exception.class)
public class OrderService {
#Autowired
private IOrderRequestRepositoryForMain orderRequestRepositoryForMain;
#Autowired
private IOrderRequestRepositoryForReplica orderRequestRepositoryForReplica;
public CustomerVisitsResponse getTotalCustomerVisitsForMonthForReplicaDataSource(Long customerId) {
List<Integer> statusIdList= new ArrayList<>();
CustomerVisitsResponse response= new CustomerVisitsResponse();
statusIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
List<Integer> sellerIdList= new ArrayList<>();
sellerIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
Date date = new Date();
String month= dateFormat.format(date)+"%";
try {
List<in.demo.order.replicadao.model.OrderEntity> orders =
orderRequestRepositoryForReplica.getOrderBycustomerIdAndBdMonth(customerId,statusIdList,month,sellerIdList);
if(orders!=null && !orders.isEmpty())
{
double total=0d;
for(in.demo.order.replicadao.model.OrderEntity order:orders)
{
total+=order.getPayableAmount();
}
response.setTotalSpent(total);
response.setTotalVisits((long)(orders.size()));
}
else {
response.setTotalSpent(0d);
response.setTotalVisits(0l);
}
} catch (Exception e) {
logger.info("Error occured while fetching getTotalCustomerVisitsForMonth customerid: " + customerId);
response.setTotalSpent(0d);
response.setTotalVisits(0l);
return response;
}
return response;
}
public CustomerVisitsResponse getTotalCustomerVisitsForMonthForMainDataSource(Long customerId) {
List<Integer> statusIdList= new ArrayList<>();
CustomerVisitsResponse response= new CustomerVisitsResponse();
statusIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
List<Integer> sellerIdList= new ArrayList<>();
sellerIdList.add(OrderServiceConstants.SOME_CONSTANT_VALUE);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM");
Date date = new Date();
String month= dateFormat.format(date)+"%";
try {
List<in.demo.order.dao.model.OrderEntity> orders =
orderRequestRepositoryForMain.getOrderBycustomerIdAndBdMonth(customerId,statusIdList,month,sellerIdList);
if(orders!=null && !orders.isEmpty())
{
double total=0d;
for(in.demo.order.dao.model.OrderEntity order:orders)
{
total+=order.getPayableAmount();
}
response.setTotalSpent(total);
response.setTotalVisits((long)(orders.size()));
}
else {
response.setTotalSpent(0d);
response.setTotalVisits(0l);
}
} catch (Exception e) {
logger.info("Error occured while fetching getTotalCustomerVisitsForMonth customerid: " + customerId);
response.setTotalSpent(0d);
response.setTotalVisits(0l);
return response;
}
return response;
}
}
Repository classes
package in.demo.order.replicadao;
IOrderRequestRepositoryForReplica
package in.demo.order.replicadao;
import in.demo.order.replicadao.model.OrderEntity;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
#Repository
public interface IOrderRequestRepositoryForReplica extends PagingAndSortingRepository<OrderEntity, Long> {
#Query(nativeQuery = true,
value = "SELECT * FROM orders ...<some query>")
public List<OrderEntity> getOrderBycustomerIdAndBdMonth(
Long customerId, List<Integer> statusIdList, String month, List<Integer> sellerIdList);
}
package in.demo.order.dao;
IOrderRequestRepositoryForMain
package in.demo.order.dao;
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.stereotype.Repository;
import in.demo.order.dao.model.OrderEntity;
#Repository
public interface IOrderRequestRepositoryForMain extends PagingAndSortingRepository<OrderEntity, Long> {
#Query(nativeQuery = true,
value = "SELECT * FROM orders ...<some query>")
public List<OrderEntity> getOrderBycustomerIdAndBdMonth(Long customerId,
List<Integer> statusIdList, String month, List<Integer> sellerIdList);
}
Same Entity in different package with different serialVersionUID
packages are:
package in.demo.order.replicadao.model;
package in.demo.order.dao.model;
OrderEntity
package in.demo.order.replicadao.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "orders")
public class OrderEntity implements Serializable {
/**
*
*/
private static final long serialVersionUID = 4667868888563693990L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique = true)
private String orderId;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
}
Controller class
OrderController
package in.demo.order.controller;
import java.util.List;
import javax.sql.DataSource;
import in.demo.order.service.OrderManagerService;
#RestController
#RequestMapping("/api/order")
public class OrderController {
#Autowired
private OrderManagerService orderManagerService;
#Autowired
private DataSource mainDataSource;
#Autowired
#Qualifier("replicaDataSource")
private DataSource replicaDataSource;
#GetMapping("/replica")
public CustomerVisitsResponse getCustomerVisitResponseForReplica() {
Long customerId = 123L;
return orderManagerService.getCustomerVisitsForMonthForReplicaDataSource(customerId);
}
#GetMapping("/main")
public CustomerVisitsResponse getCustomerVisitResponseForMain() {
Long customerId = 123L;
return orderManagerService.getCustomerVisitsForMonthForMainDataSource(customerId);
}
#GetMapping("/maindatasource")
public String getMainDataSource() {
return mainDataSource.toString();
}
#GetMapping("/replicadatasource")
public String getReplicaDataSource() {
return replicaDataSource.toString();
}
}
I have checked manually in both Database for the query I am running. Data is present. But when I am running from postman to test
for replica, I am getting
Method threw 'org.springframework.dao.InvalidDataAccessResourceUsageException' exception. caused by org.hibernate.exception.SQLGrammarException: could not execute query
for main, I am getting
Transaction was marked for rollback only; cannot commit; nested exception is org.hibernate.TransactionException: Transaction was marked for rollback only; cannot commit
When I am using one datasource, the query is working fine.
The issue was with Entity class column name mapping issue, previously we were not mentioning #Column(name="column_name") , once I added the annotation, it started to work. But still I am confused how it is working fine when using single Data source

Rollback is not working in #Transactional annotated service. Spring + Hibernate

In my code the service method savePerson is annotated with #Transactional. Inside this method a Person entity is persisted and inmediately a Runtime exception is intentionally throwed. I suposse the transaction should not be commited but the Person entity is persisted in database....rollback is not working and I dont know why.
This is my Hibernate Configuration:
package newp;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
#Configuration
#EnableTransactionManagement
public class HibernateConf {
#Bean
public LocalSessionFactoryBean sessionFactory() {
LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setPackagesToScan(new String[]{"newp"});
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/poas");
dataSource.setUsername("admin");
dataSource.setPassword("admin");
return dataSource;
}
#Bean
public PlatformTransactionManager hibernateTransactionManager() {
HibernateTransactionManager transactionManager= new HibernateTransactionManager();
transactionManager.setSessionFactory(sessionFactory().getObject());
return transactionManager;
}
private final Properties hibernateProperties() {
Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
hibernateProperties.setProperty("hibernate.show_sql", "true");
return hibernateProperties;
}
}
This is my service:
package newp.services;
import javax.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import newp.dao.PersonDao;
import newp.model.Person;
#Service
public class PersonService{
#Autowired
PersonDao dao;
#Transactional
public void savePerson(Person p) {
dao.savePerson(p);
throw new RuntimeException();
}
}
The DAO
package newp.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import newp.entities.PersonEntity;
import newp.model.Person;
#Repository
public class PersonDao {
#Autowired
SessionFactory sessionFactory;
public void savePerson(Person person) {
Session s = sessionFactory.getCurrentSession();
PersonEntity p=new PersonEntity();
p.setAge(person.getAge());
p.setName(person.getName());
p.setSurname(person.getSurname());
s.saveOrUpdate(p);
}
}
You are probably using tables with the MyISAM storage engine which does not support transactions: https://stackoverflow.com/a/8036049/412446

when using miltiple datasource hibernate envers are not working

When I use only one datasource, hibernate envers are working well(not using any config.java. just set application.properties). But Using multiple datasource(with config.java, same DB, different user), envers are not working and logged oracle error message ORA-00942.
audited table is in DB#1. How can I do?
spring boot 1.5.6
application.properties
#################################
# DataBase #1 (Default)
#################################
spring.datasource.initialize=true
spring.datasource.url=jdbc:oracle:thin:#localhost:1521:orcl
spring.datasource.username=id_1
spring.datasource.password=pw_1
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
#################################
# DataBase #2(Additional)
#################################
db2.datasource.initialize=true
db2.datasource.url=jdbc:oracle:thin:#localhost:1521:orcl
db2.datasource.username=db_2
db2.datasource.password=pw_2
db2.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
config.java
package com.dev;
import javax.sql.DataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
#Configuration
public class DataBaseConfig {
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource defaultDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "defaultEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean entityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(defaultDataSource())
.packages("com.dev.core.**", "com.dev.ext.**")
.build();
}
#Primary
#Bean(name = "defaultTransactionManager")
PlatformTransactionManager transactionManager(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(entityManagerFactory(builder).getObject());
}
#Configuration
#EnableJpaRepositories(basePackages= {"com.dev.core.**", "com.dev.ext.**"},
entityManagerFactoryRef = "defaultEntityManagerFactory", transactionManagerRef = "defaultTransactionManager")
static class DefaultJpaRepositoriesConfig {
}
/*Additional Data Source - NCRM*/
#Bean
#ConfigurationProperties(prefix = "db2.datasource")
public DataSource ncrmDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "ncrmEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean ncrmEntityManagerFactory(EntityManagerFactoryBuilder builder) {
return builder.dataSource(ncrmDataSource())
.packages("com.dev.ext.ncrm.*.domain")
.build();
}
#Bean(name = "ncrmTtransactionManager")
PlatformTransactionManager ncrmTransactionManagerMain(EntityManagerFactoryBuilder builder) {
return new JpaTransactionManager(ncrmEntityManagerFactory(builder).getObject());
}
#Configuration
#EnableJpaRepositories(
basePackages="com.dev.ext.ncrm.*.repo",
entityManagerFactoryRef = "ncrmEntityManagerFactory",
transactionManagerRef = "ncrmTtransactionManager")
static class ncrmJpaRepositoriesConfig {
}
}
defaultDO.java
package com.dev.core.domain;
import java.sql.Timestamp;
import javax.persistence.Column;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;
import org.hibernate.annotations.NamedNativeQuery;
import org.hibernate.envers.AuditTable;
import org.hibernate.envers.Audited;
import lombok.Data;
#Data
#Entity
#Table(name = "tb_category")
#Audited
#AuditTable("tx_category_audit")
public class CategoryDO {
//codes
}
First add hibernate dialect at application.properties file like below for both data source:
spring.datasource.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
spring.secondDatasource.hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
Then Please rewrite the configuration like below
package com.multisource.poc.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.sql.DataSource;
import java.util.Properties;
#Configuration
public class ApplicationConfiguration {
#Value("${spring.datasource.hibernate.dialect}")
private String oracleDialect;
#Value("${spring.secondDatasource.hibernate.dialect}")
private String postgresDialect;
#Primary
#Bean(name = "oracleDB")
#ConfigurationProperties(prefix = "spring.datasource")
public DataSource oracleDataSource() {
return DataSourceBuilder.create().build();
}
#Primary
#Bean(name = "oracleEM")
public LocalContainerEntityManagerFactoryBean oracleEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", oracleDialect);
LocalContainerEntityManagerFactoryBean emf = builder
.dataSource(oracleDataSource())
.packages("entitypackageOne")
.persistenceUnit("oraclePU")
.build();
emf.setJpaProperties(properties);
return emf;
}
#Bean(name = "postgresDB")
#ConfigurationProperties(prefix = "spring.secondDatasource")
public DataSource postgresDataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "postgresEM")
public LocalContainerEntityManagerFactoryBean postgresEntityManagerFactory(
EntityManagerFactoryBuilder builder) {
Properties properties = new Properties();
properties.setProperty("hibernate.dialect", postgresDialect);
LocalContainerEntityManagerFactoryBean emf = builder
.dataSource(postgresDataSource())
.packages("entitypackageTwo")
.persistenceUnit("postgresPU")
.build();
emf.setJpaProperties(properties);
return emf;
}
}
Now you have two different EntityManager to use. The sample would be like
#Repository
public class OracleDao implements InterOracle {
private EntityManager entityManager;
#Autowired
public OracleDao(#Qualifier("oracleEM") EntityManager entityManager) {
this.entityManager = entityManager;
}
}
#Repository
public class PostgresDao implements InterPostGres{
private static final Logger LOG
= LoggerFactory.getLogger(PostgresDao.class);
private EntityManager entityManager;
#Autowired
public PostgresDao(#Qualifier("postgresEM") EntityManager entityManager) {
this.entityManager = entityManager;
}
}
This is how my application is working using two different datasource.
Does user db_2 / pw_2 have the required permission to access the DB?

Error creating bean, Injection of autowired dependencies failed - 500 Internal Server Error

I have created a new Spring project and I have some trouble when I run the application. I am new to Spring development and I thing that the annotations are not placed properly. Any detailed explanation would be great for me for better understating. I am currently reading Spring in action, but if any other book or tutorial seems more accurate, please leave me a comment :)[this is the error that I am getting - 500 Internal Server Error].
This is my project:
HelloWorldConfiguration
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
#EnableWebMvc
#ComponentScan(basePackages = "com.websystique.springmvc")
public class HelloWorldConfiguration {
#Bean(name="HelloWorld")
public ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setViewClass(JstlView.class);
viewResolver.setPrefix("/WEB-INF/views/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
HelloWordInitializer
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class HelloWorldInitializer implements WebApplicationInitializer {
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
ctx.register(HelloWorldConfiguration.class);
ctx.setServletContext(container);
ServletRegistration.Dynamic servlet = container.addServlet(
"dispatcher", new DispatcherServlet(ctx));
servlet.setLoadOnStartup(1);
servlet.addMapping("/");
}
}
HelloWorldController
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import service.StudentService;
import java.util.HashMap;
import java.util.Map;
#Configuration
#Controller
#ComponentScan(basePackages = "com.websystique.springmvc")
#RequestMapping("/")
public class HelloWorldController {
public HelloWorldController(){
}
#Autowired
private StudentService studentService;
private Map<String, Student> persoaneAdaugate = new HashMap<String, Student>();
#RequestMapping(method = RequestMethod.GET)
public String sayHello(ModelMap model) {
model.addAttribute("greeting", "Hello World from Spring 4 MVC");
return "welcome";
}
#RequestMapping(value = "/helloagain", method = RequestMethod.GET)
public String sayHelloAgain(ModelMap model) {
model.addAttribute("greeting", "Hello World Again, from Spring 4 MVC");
return "welcome";
}
/***
* #ModelAttribute = binds a method parameter or a method return value to a named model attribute and then exposes it to a web view.
* #param student
* #param result
* #param modelMap
* #return
* That is, #ModelAttribute methods are invoked before the controller methods annotated with #RequestMapping are invoked.
* The logic behind the sequence is that, the model object has to be created before any processing starts inside the controller methods.
*/
#RequestMapping(value="/", method = RequestMethod.POST)
public String addStudent(#ModelAttribute("addStudent") Student student, BindingResult result, ModelMap modelMap){
if(result.hasErrors()){
return "error";
}
else {
studentService.addStudent(student);
}
/*modelMap.addAttribute("nume", student.getNume());
modelMap.addAttribute("prenume", student.getPrenume());
persoaneAdaugate.put(student.getNume(), student);
System.out.println("Persoane adaugate: " + persoaneAdaugate +"\n");
System.out.println("nume: " + student.getNume()+" si prenume: " +student.getPrenume());
*/
return "success";
}
}
StudentDao
import com.websystique.springmvc.model.Student;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public interface StudentDao {
List<Student> getAllStudents();
void addStudent(Student student);
}
StudentDaoImpl
import com.websystique.springmvc.model.Student;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Repository("studentDao")
#Service
#Transactional
public class StudentDaoImpl implements StudentDao{
#Autowired
private SessionFactory sessionFactory;
public List<Student> getAllStudents() {
return null;
// return sessionFactory.getCurrentSession().createQuery("from Date").list();
}
public void addStudent(Student student) {
sessionFactory.getCurrentSession().saveOrUpdate(student);
}
}
Student
import org.hibernate.validator.constraints.NotEmpty;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
#Entity
#Table(name="DATE")
public class Student implements Serializable{
#Id
#NotEmpty
#Column(name="nume", unique=true, nullable=false )
private String nume;
#NotEmpty
#Column(name="prenume", nullable = false)
private String prenume;
protected Student(){
}
Student(String nume, String prenume){
this.prenume=prenume;
this.nume=nume;
}
public String getNume(){
return nume;
}
public void setNume(String nume){
this.nume=nume;
}
public String getPrenume(){
return prenume;
}
public void setPrenume(String prenume){
this.prenume=prenume;
}
#Override
public String toString(){
return "Numele adaugat: nume= " + nume +" si prenume= " +prenume;
}
}
StudentService
import com.websystique.springmvc.model.Student;
import org.springframework.stereotype.Component;
import java.util.List;
#Component
public interface StudentService {
List<Student> getAllStudents();
void addStudent(Student student);
}
StudentServiceImpl
import com.websystique.springmvc.dao.StudentDao;
import com.websystique.springmvc.model.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#Transactional
public class StudentServiceImpl implements StudentService {
#Autowired
private StudentDao studentDao;
#Transactional
public List<Student> getAllStudents() {
return studentDao.getAllStudents();
}
public void addStudent(Student student) {
studentDao.addStudent(student);
}
}

Spring security 3.2.5 and token based authentication

I'm trying to secure a REST API using Spring security 3.2.5 and a java based configuration.
Actually i've found many examples developed with an "old" xml approach, but nothing with a complete java configuration.
Where can i find some useful tutorial?
The project creates a REST API and some jsp usesd to allow the admin to populate an underlyin DB (Hibernate is used as ORM):
Here is my Config class:
package com.idk.fantappapaback.spring;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.tomcat.dbcp.dbcp.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.Import; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.web.multipart.support.StandardServletMultipartResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; import org.springframework.web.servlet.view.JstlView; import org.springframework.web.servlet.view.UrlBasedViewResolver;
import com.google.common.base.Preconditions; import com.idk.fantappapaback.spring.security.SecurityConfig;
#Configuration #EnableWebMvc #EnableTransactionManagement #PropertySource({ "classpath:persistence-mysql.properties" }) #ComponentScan({ "com.idk.fantappapaback.persistence","com.idk.fantappapaback.rest","com.idk.fantappapaback.spring.controllers","com.idk.fantappapaback.spring.security" }) #Import({ SecurityConfig.class }) public class BackEndConfig extends WebMvcConfigurerAdapter{
#Autowired
private Environment env;
public BackEndConfig() {
super();
}
//l'application context estrae il session factory da questo bean
#Bean
public LocalSessionFactoryBean sessionFactory() {
final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
sessionFactory.setDataSource(restDataSource());
sessionFactory.setPackagesToScan(new String[] { "com.idk.fantappapaback.persistence.model" });
sessionFactory.setHibernateProperties(hibernateProperties());
return sessionFactory;
}
#Bean
public DataSource restDataSource() {
final BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
return dataSource;
}
#Bean
#Autowired
public HibernateTransactionManager transactionManager(final SessionFactory sessionFactory) {
final HibernateTransactionManager txManager = new HibernateTransactionManager();
txManager.setSessionFactory(sessionFactory);
return txManager;
}
#Bean
public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
return new PersistenceExceptionTranslationPostProcessor();
}
final Properties hibernateProperties() {
final Properties hibernateProperties = new Properties();
hibernateProperties.setProperty("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
//***Proprieta per l'output delle query in sql che qui disabilito
// hibernateProperties.setProperty("hibernate.show_sql", "true");
// hibernateProperties.setProperty("hibernate.format_sql", "true");
// hibernateProperties.setProperty("hibernate.globally_quoted_identifiers", "true");
return hibernateProperties;
}
#Bean
public UrlBasedViewResolver setupViewResolver() {
UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setPrefix("WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setViewClass(JstlView.class);
return resolver;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
#Bean
public StandardServletMultipartResolver multipartResolver(){
return new StandardServletMultipartResolver();
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/resources/**")
.addResourceLocations("/resources/"); // registry.addResourceHandler("/css/**") // .addResourceLocations("/css/"); // registry.addResourceHandler("/img/**") // .addResourceLocations("/img/");
registry.addResourceHandler("/js/**")
.addResourceLocations("/js/");
}
}
this is my very basic Security config that i use to have a form log in on the jsp views:
package com.idk.fantappapaback.spring.security;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
#Import({ SecurityConfig.class }) nella BackEndConfig #Configuration #EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter{ #Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("masquenada").password("123456").roles("USER"); // auth.inMemoryAuthentication().withUser("masquenada").password("123456").roles("ADMIN"); auth.inMemoryAuthentication().withUser("masquenada").password("123456").roles("SUPERADMIN"); }
#Override protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() // .antMatchers("/players/**").access("hasRole('ROLE_USER')") .antMatchers("/createSeason/**").access("hasRole('ROLE_SUPERADMIN')") .and().formLogin().permitAll() .and().httpBasic();
} }
here is my SecurityWebApplicationInitializer :
package com.idk.fantappapaback.spring.security;
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
The main question is : how to add the token based autorization?
I've added Spring oAuth 2 and Spring integration to my pom but i need some hint about introducing spring oAuth keeping the form login.
You need to "configure" your SecurityWebApplicatioInitializer.
http://spring.io/blog/2013/07/03/spring-security-java-config-preview-web-security/

Resources