Spring Batch ResourcelessTransactionManager messes with persistence.xml? - spring

I am working on an application and have been asked to implement a scheduled spring batch job. I have set up a configuration file where I set a #Bean ResourcelessTransactionManager but it seems to mess with the persistence.xml.
There is already a persistence xml in an other module, there is no compilation error. I get a NoUniqueBeanDefinitionException when I am requesting a page that returns a view item.
This is the error:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [org.springframework.transaction.PlatformTransactionManager] is defined: expected single matching bean but found 2: txManager,transactionManager
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:365)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:331)
at org.springframework.transaction.interceptor.TransactionAspectSupport.determineTransactionManager(TransactionAspectSupport.java:366)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:271)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:653)
at com.mypackage.services.MyClassService$$EnhancerBySpringCGLIB$$9e8bf16f.registryEvents(<generated>)
at com.mypackage.controllers.MyClassSearchView.init(MyClassSearchView.java:75)
... 168 more
Is there a way to tell spring batch to use the data source defined in the persistence.xml of the other module or maybe is this caused by something else?

I created separate BatchScheduler java class as below and included it in BatchConfiguration java class. I am sharing both the classes. BatchConfiguration contains another jpaTransactionManager.
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
#Configuration
#EnableScheduling
public class BatchScheduler {
#Bean
public ResourcelessTransactionManager resourcelessTransactionManager() {
return new ResourcelessTransactionManager();
}
#Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(
ResourcelessTransactionManager resourcelessTransactionManager) throws Exception {
MapJobRepositoryFactoryBean factory = new
MapJobRepositoryFactoryBean(resourcelessTransactionManager);
factory.afterPropertiesSet();
return factory;
}
#Bean
public JobRepository jobRepository(
MapJobRepositoryFactoryBean factory) throws Exception {
return factory.getObject();
}
#Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
return launcher;
}
}
BatchConfiguration contains another jpaTransactionManager.
import java.io.IOException;
import java.util.Date;
import java.util.Properties;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.database.JpaItemWriter;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
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.Database;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ConcurrentTaskScheduler;
import org.springframework.transaction.PlatformTransactionManager;
import trade.api.common.constants.Constants;
import trade.api.entity.SecurityEntity;
import trade.api.trade.batch.item.processor.SecurityItemProcessor;
import trade.api.trade.batch.item.reader.NseSecurityReader;
import trade.api.trade.batch.notification.listener.SecurityJobCompletionNotificationListener;
import trade.api.trade.batch.tasklet.SecurityReaderTasklet;
import trade.api.vo.SecurityVO;
#Configuration
#EnableBatchProcessing
#EnableScheduling
#Import({OhlcMonthBatchConfiguration.class, OhlcWeekBatchConfiguration.class, OhlcDayBatchConfiguration.class, OhlcMinuteBatchConfiguration.class})
public class BatchConfiguration {
private static final String OVERRIDDEN_BY_EXPRESSION = null;
/*
Load the properties
*/
#Value("${database.driver}")
private String databaseDriver;
#Value("${database.url}")
private String databaseUrl;
#Value("${database.username}")
private String databaseUsername;
#Value("${database.password}")
private String databasePassword;
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
private JobLauncher jobLauncher;
#Bean
public TaskScheduler taskScheduler() {
return new ConcurrentTaskScheduler();
}
//second, minute, hour, day of month, month, day(s) of week
//#Scheduled(cron = "0 0 21 * * 1-5") on week days
#Scheduled(cron="${schedule.insert.security}")
public void importSecuritySchedule() throws Exception {
System.out.println("Job Started at :" + new Date());
JobParameters param = new JobParametersBuilder().addString("JobID",
String.valueOf(System.currentTimeMillis())).toJobParameters();
JobExecution execution = jobLauncher.run(importSecuritesJob(), param);
System.out.println("Job finished with status :" + execution.getStatus());
}
#Bean SecurityJobCompletionNotificationListener securityJobCompletionNotificationListener() {
return new SecurityJobCompletionNotificationListener();
}
//Import Equity OHLC End
//Import Equity Start
// tag::readerwriterprocessor[]
#Bean
public SecurityReaderTasklet securityReaderTasklet() {
return new SecurityReaderTasklet();
}
#Bean
#StepScope
public NseSecurityReader<SecurityVO> nseSecurityReader(#Value("#{jobExecutionContext["+Constants.SECURITY_DOWNLOAD_FILE+"]}") String pathToFile) throws IOException {
NseSecurityReader<SecurityVO> reader = new NseSecurityReader<SecurityVO>();
reader.setLinesToSkip(1);
reader.setResource(new FileSystemResource(pathToFile));
reader.setLineMapper(new DefaultLineMapper<SecurityVO>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames(new String[] { "symbol", "nameOfCompany", "series", "dateOfListing", "paidUpValue", "marketLot", "isinNumber", "faceValue" });
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<SecurityVO>() {{
setTargetType(SecurityVO.class);
}});
}});
return reader;
}
#Bean
public SecurityItemProcessor processor() {
return new SecurityItemProcessor();
}
#Bean
public JpaItemWriter<SecurityEntity> writer() {
JpaItemWriter<SecurityEntity> writer = new JpaItemWriter<SecurityEntity>();
writer.setEntityManagerFactory(entityManagerFactory().getObject());
return writer;
}
// end::readerwriterprocessor[]
// tag::jobstep[]
#Bean
public Job importSecuritesJob() throws IOException {
return jobBuilderFactory.get("importSecuritesJob")
.incrementer(new RunIdIncrementer())
.listener(securityJobCompletionNotificationListener())
.start(downloadSecurityStep())
.next(insertSecurityStep())
.build();
}
#Bean
public Step downloadSecurityStep() throws IOException {
return stepBuilderFactory.get("downloadSecurityStep")
.tasklet(securityReaderTasklet())
.build();
}
#Bean
public Step insertSecurityStep() throws IOException {
return stepBuilderFactory.get("insertSecurityStep")
.transactionManager(jpaTransactionManager())
.<SecurityVO, SecurityEntity> chunk(100)
.reader(nseSecurityReader(OVERRIDDEN_BY_EXPRESSION))
.processor(processor())
.writer(writer())
.build();
}
// end::jobstep[]
//Import Equity End
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(databaseDriver);
dataSource.setUrl(databaseUrl);
dataSource.setUsername(databaseUsername);
dataSource.setPassword(databasePassword);
return dataSource;
}
#Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean lef = new LocalContainerEntityManagerFactoryBean();
lef.setPackagesToScan("trade.api.entity");
lef.setDataSource(dataSource());
lef.setJpaVendorAdapter(jpaVendorAdapter());
lef.setJpaProperties(new Properties());
return lef;
}
#Bean
public JpaVendorAdapter jpaVendorAdapter() {
HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
jpaVendorAdapter.setDatabase(Database.MYSQL);
jpaVendorAdapter.setGenerateDdl(true);
jpaVendorAdapter.setShowSql(false);
jpaVendorAdapter.setDatabasePlatform("org.hibernate.dialect.MySQLDialect");
return jpaVendorAdapter;
}
#Bean
#Qualifier("jpaTransactionManager")
public PlatformTransactionManager jpaTransactionManager() {
return new JpaTransactionManager(entityManagerFactory().getObject());
}
#Bean
public static PropertySourcesPlaceholderConfigurer dataProperties(Environment environment) throws IOException {
String[] activeProfiles = environment.getActiveProfiles();
final PropertySourcesPlaceholderConfigurer ppc = new PropertySourcesPlaceholderConfigurer();
ppc.setLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:application-"+activeProfiles[0]+".properties"));
return ppc;
}
//// Import Security End
}

Problem solved. There was a PlatformTransactionManager bean located in an other configuration file. I set it as #Primary and now the problem is fixed. Thanks everyone for the help.

Related

How to add AsyncItemWriter in Spring Batch to a Step correctly?

In a Spring Batch Job like the following I'm trying to use an AsyncWriter
#Bean
public Step readWriteStep() throws Exception {
return stepBuilderFactory.get("readWriteStep")
.listener(listener)
.<Data, Data>chunk(10)
.reader(dataItemReader())
.writer(dataAsyncWriter())
.build();
}
#Bean
public AsyncItemWriter<Data> dataAsyncWriter() throws Exception {
AsyncItemWriter<Data> asyncItemWriter = new AsyncItemWriter<>();
asyncItemWriter.setDelegate(dataItemWriter);
asyncItemWriter.afterPropertiesSet();
return asyncItemWriter;
}
If I try like this intelliJ complains:
Required type: ItemWriter <? super Data>
Provided: AsyncItemWriter <Data>
When I change .<Data, Data>chunk(10) to .<Data, Future<Data>>chunk(10) intelliJ does not make any warning, but when I run the Job, I get the following Exception:
java.lang.ClassCastException: Data cannot be cast to class java.util.concurrent.Future Data is in unnamed module of loader 'app';
java.util.concurrent.Future is in module java.base of loader 'bootstrap'
For what is the first and the second parameter here? .<Data, Data>chunk(10)?
Are these two parameters for what the processor takes and the second what the processor is giving back?
How do I solve this Problem?
Your example should compile if you change the step definition to use the following:
.<Data, Future<Data>>chunk(10)
That said, I'm not sure this will work correctly at runtime because the AsyncItemWriter is expected to unwrap items from their enclosing Futures, where these Futures are created by an AsyncItemProcessor.
In other words, AsyncItemWriter and AsyncItemProcessor should be used in conjunction for this pattern to work. Here is a quick example with both of them:
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.integration.async.AsyncItemProcessor;
import org.springframework.batch.integration.async.AsyncItemWriter;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
#Configuration
#EnableBatchProcessing
public class SO72477556 {
#Bean
public ItemReader<Data> dataItemReader() {
return new ListItemReader<Data>(Arrays.asList());
}
#Bean
public ItemProcessor<Data, Data> dataItemProcessor() {
return new ItemProcessor<Data, Data>() {
#Override
public Data process(Data item) throws Exception {
return item;
}
};
}
#Bean
public AsyncItemProcessor<Data, Data> asyncDataItemProcessor() {
AsyncItemProcessor<Data, Data> asyncItemProcessor = new AsyncItemProcessor<>();
asyncItemProcessor.setDelegate(dataItemProcessor());
asyncItemProcessor.setTaskExecutor(new SimpleAsyncTaskExecutor());
return asyncItemProcessor;
}
#Bean
public ItemWriter<Data> dataItemWriter() {
return new ItemWriter<Data>() {
#Override
public void write(List<? extends Data> items) throws Exception {
}
};
}
#Bean
public AsyncItemWriter<Data> dataAsyncWriter() throws Exception {
AsyncItemWriter<Data> asyncItemWriter = new AsyncItemWriter<>();
asyncItemWriter.setDelegate(dataItemWriter());
asyncItemWriter.afterPropertiesSet();
return asyncItemWriter;
}
#Bean
public Step readWriteStep(StepBuilderFactory stepBuilderFactory) throws Exception {
return stepBuilderFactory.get("readWriteStep")
.<Data, Future<Data>>chunk(10)
.reader(dataItemReader())
.processor(asyncDataItemProcessor())
.writer(dataAsyncWriter())
.build();
}
#Bean
public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) throws Exception {
return jobs.get("job")
.start(readWriteStep(steps))
.build();
}
public static void main(String[] args) throws Exception {
ApplicationContext context = new AnnotationConfigApplicationContext(SO72477556.class);
JobLauncher jobLauncher = context.getBean(JobLauncher.class);
Job job = context.getBean(Job.class);
jobLauncher.run(job, new JobParameters());
}
static class Data {}
}

spring batch : typeMismatch.java.sql.Date,typeMismatch

i'm trying to send this csv file to database with spring batch
users.csv
2021-06-22,test1#gmail.com, testFullname1, testMatricule1, 1234, testUsername1
2021-06-22,test2#gmail.com, testFullname2, testMatricule2, 0000, testUsername2
and i have this error
Failed to convert property value of type 'java.lang.String' to required type 'java.sql.Date' for property
here's batchConfig
package sofrecom.collaborateur.config;
import javax.sql.DataSource;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.batch.item.file.mapping.DefaultLineMapper;
import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import sofrecom.collaborateur.model.DAOUser;
#Configuration
#EnableBatchProcessing
public class BatchConfiguration {
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
public DataSource dataSource;
#Bean
public FlatFileItemReader<DAOUser> reader() {
FlatFileItemReader<DAOUser> reader = new FlatFileItemReader<DAOUser>();
reader.setResource(new ClassPathResource("users.csv"));
reader.setLineMapper(new DefaultLineMapper<DAOUser>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames(new String[] { "dateIntegration","email","fullname","matricule","password","username" });
}});
setFieldSetMapper(new BeanWrapperFieldSetMapper<DAOUser>() {{
setTargetType(DAOUser.class);
}});
}});
return reader;
}
#Bean
public UserItemProcessor processor() {
return new UserItemProcessor();
}
#Bean
public JdbcBatchItemWriter<DAOUser> writer() {
JdbcBatchItemWriter<DAOUser> writer = new JdbcBatchItemWriter<DAOUser>();
writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<DAOUser>());
writer.setSql("INSERT INTO user ( date_integration,email,fullname,matricule,password,username) VALUES ( :dateIntegration,:email,:fullname,:matricule,:password,:username)");
writer.setDataSource(dataSource);
return writer;
}
#Bean
public Job importUserJob(JobCompletionNotificationListener listener) {
return jobBuilderFactory.get("importUserJob")
.incrementer(new RunIdIncrementer())
.listener(listener)
.flow(step1())
.end()
.build();
}
#Bean
public Step step1() {
return stepBuilderFactory.get("step1")
.<DAOUser, DAOUser> chunk(10)
.reader(reader())
.processor(processor())
.writer(writer())
.build();
}
}
and this is user Item proccessor
package sofrecom.collaborateur.config;
import java.sql.Date;
import java.text.SimpleDateFormat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import sofrecom.collaborateur.model.DAOUser;
public class UserItemProcessor implements ItemProcessor<DAOUser, DAOUser> {
private static final Logger log = LoggerFactory.getLogger(UserItemProcessor.class);
#Autowired
private PasswordEncoder bcryptEncoder;
#Override
public DAOUser process(final DAOUser person) throws Exception {
final String password = bcryptEncoder.encode(person.getUsername());
final DAOUser transformedPerson = new DAOUser(person.getDateIntegration(),person.getEmail(),person.getFullname(),person.getMatricule(),password,person.getUsername());
log.info("Converting (" + person + ") into (" + transformedPerson + ")");
return transformedPerson;
}
}
any solution please !!
The problem is that the BeanWrapperFieldSetMapper does not know, by default, how to convert a String like 2021-06-22 to an object of type java.sql.Date (which is the field dateIntegration) in your domain object DAOUser. The way to tell this mapper how to deal with custom conversions is by registering a ConversionService. This conversion service should have a converter from String to java.sql.Date registered in it. Here is a quick example:
#Bean
public FlatFileItemReader<DAOUser> reader() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new Converter<String, Date>() { // java.sql.Date
#Override
public Date convert(String s) {
return Date.valueOf(s);
}
});
BeanWrapperFieldSetMapper<DAOUser> fieldSetMapper = new BeanWrapperFieldSetMapper<>();
fieldSetMapper.setConversionService(conversionService);
fieldSetMapper.setTargetType(DAOUser.class);
FlatFileItemReader<DAOUser> reader = new FlatFileItemReader<>();
reader.setResource(new ClassPathResource("users.csv"));
reader.setLineMapper(new DefaultLineMapper<DAOUser>() {{
setLineTokenizer(new DelimitedLineTokenizer() {{
setNames(new String[] { "dateIntegration","email","fullname","matricule","password","username" });
}});
setFieldSetMapper(fieldSetMapper);
}});
return reader;
}
You can find a complete example based on what you shared in this repository.

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

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.

Quartz job not running

I'm using the following beans for scheduling the quartz jobs:
package com.sap.brms.repositoryservice.cp.cf.app.config;
import java.io.IOException;
import java.util.Properties;
import javax.inject.Inject;
import javax.sql.DataSource;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
#Configuration
public class SchedulerConfig {
#Bean
public JobFactory jobFactory(ApplicationContext applicationContext)
{
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public Scheduler schedulerFactoryBean(#Qualifier("applicationDataSource") DataSource dataSource, JobFactory jobFactory,
#Qualifier("sampleJobTrigger") Trigger sampleJobTrigger) throws Exception {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// this allows to update triggers in DB when updating settings in config file:
factory.setOverwriteExistingJobs(true);
factory.setDataSource(dataSource);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
factory.afterPropertiesSet();
Scheduler scheduler = factory.getScheduler();
scheduler.setJobFactory(jobFactory);
scheduler.scheduleJob((JobDetail) sampleJobTrigger.getJobDataMap().get("jobDetail"), sampleJobTrigger);
scheduler.start();
return scheduler;
}
#Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
#Bean
public JobDetailFactoryBean sampleJobDetail() {
return createJobDetail(SampleJob.class);
}
#Bean(name = "sampleJobTrigger")
public CronTriggerFactoryBean sampleJobTrigger(#Qualifier("sampleJobDetail") JobDetail jobDetail,
#Value("0 * * ? * *") String cronExpression) {
return createCronTrigger(jobDetail, "0 * * ? * *");
}
private static JobDetailFactoryBean createJobDetail(Class jobClass) {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(jobClass);
// job has to be durable to be stored in DB:
factoryBean.setDurability(true);
return factoryBean;
}
private static SimpleTriggerFactoryBean createTrigger(JobDetail jobDetail, long pollFrequencyMs) {
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(0L);
factoryBean.setRepeatInterval(pollFrequencyMs);
factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
// in case of misfire, ignore all missed triggers and continue :
factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
return factoryBean;
}
// Use this method for creating cron triggers instead of simple triggers:
private static CronTriggerFactoryBean createCronTrigger(JobDetail jobDetail, String cronExpression) {
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setCronExpression(cronExpression);
factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
return factoryBean;
}
}
My quartz properties are as following:
org.quartz.scheduler.instanceName=spring-boot-quartz-demo
org.quartz.scheduler.instanceId=AUTO
org.quartz.threadPool.threadCount=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.tablePrefix=RULE_QRTZ_
org.quartz.scheduler.classLoadHelper.class=org.quartz.simpl.ThreadContextClassLoadHelper
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000
The class SampleJob is:
public class SampleJob implements Job {
private static Logger logger = LoggerFactory.getLogger(SampleJob.class);
public SampleJob() {}
#Override
public void execute(JobExecutionContext context) throws JobExecutionException {
logger.info("Metering Job called");
}
}
I have a postgres database installed on my local system, and when I run the spring boot application, the application runs however the SampleJob is never triggered. The application is a spring boot application with the version being 1.2.5.

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