I am new to Spring Boot. I am trying to achieve a PropertySourcesPlaceholderConfigurer configuration that would return properties from a property file as well as database table. Here's what I wrote:
#Configuration
#PropertySource(value = { "classpath:application.properties" }, ignoreResourceNotFound = false)
public class SpringPropertiesConfig implements EnvironmentAware {
private static final Logger log = LoggerFactory.getLogger(SpringPropertiesConfig.class);
#Inject
private org.springframework.core.env.Environment env;
#PostConstruct
public void initializeDatabasePropertySourceUsage() {
MutablePropertySources propertySources = ((ConfigurableEnvironment) env).getPropertySources();
System.out.println("propertySources : " + propertySources);
try {
// dataSource, Table Name, Key Column, Value Column
DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration(dataSource(),
"APPLICATION_CONFIGURATION", "KEY", "VALUE");
Properties dbProps = ConfigurationConverter.getProperties(databaseConfiguration);
PropertiesPropertySource dbPropertySource = new PropertiesPropertySource("dbPropertySource", dbProps);
propertySources.addFirst(dbPropertySource);
} catch (Exception e) {
log.error("Error during database properties setup", e);
throw new RuntimeException(e);
}
}
#Bean(name = "pspc")
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer pspc = new PropertySourcesPlaceholderConfigurer();
pspc.setIgnoreUnresolvablePlaceholders(true);
// System.out.println("propertySourcesPlaceholderConfigurer = " +
// pspc.getAppliedPropertySources());
return pspc;
}
#Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(env.getProperty("dev.datasource.driver-class-name"));
dataSource.setUrl(env.getProperty("dev.datasource.url"));
dataSource.setUsername(env.getProperty("dev.datasource.username"));
dataSource.setPassword(env.getProperty("dev.datasource.password"));
return dataSource;
}
#Override
public void setEnvironment(Environment paramEnvironment) {
this.env = paramEnvironment;
}
}
I found that properties from application.properties were getting resolved correctly.
#Value("${spnego.defaultRealm}")
private String defRealm;
Here, 'defRealm' contained the correct value. However properties from database were not getting resolved.
#Value("${enviromentName}")
private String envir;
If I print the value of envir, it prints '${enviromentName}'.
In the SpringPropertiesConfig class, the table is getting read correctly and the Properties object 'dbProps' prints all the rows in the APPLICATION_CONFIGURATION table.
Any ideas?
Thank you M. Deinum, I followed your suggestion and implemented the following :
public class SpringPropertiesConfig implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public DataSource getDataSource(org.springframework.core.env.PropertySource<?> propSrc) {
String profile = (String) propSrc.getProperty("spring.profiles.active");
if (profile.equals("dev")) {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName((String) propSrc.getProperty("dev.datasource.driver-class-name"));
dataSource.setUrl((String) propSrc.getProperty("dev.datasource.url"));
dataSource.setUsername((String) propSrc.getProperty("dev.datasource.username"));
dataSource.setPassword((String) propSrc.getProperty("dev.datasource.password"));
return dataSource;
} else if (profile.equals("prod")) {
JndiDataSourceLookup dataSourceLookup = new JndiDataSourceLookup();
DataSource dataSource = dataSourceLookup
.getDataSource((String) propSrc.getProperty("prd.datasource.jndi-name"));
return dataSource;
}
return null;
}
#Override
public void initialize(ConfigurableApplicationContext ctx) {
org.springframework.core.env.PropertySource<?> p = ctx.getEnvironment().getPropertySources()
.get("applicationConfigurationProperties");
DatabaseConfiguration databaseConfiguration = new DatabaseConfiguration(getDataSource(p),
"APPLICATION_CONFIGURATION", "KEY", "VALUE");
System.out.println("databaseConfiguration created : " + databaseConfiguration);
Properties dbProps = ConfigurationConverter.getProperties(databaseConfiguration);
System.out.println("dbProps=" + dbProps);
PropertiesPropertySource dbPropertySource = new PropertiesPropertySource("dbPropertySource", dbProps);
ctx.getEnvironment().getPropertySources().addFirst(dbPropertySource);
}
}
But what i am not sure is whether
org.springframework.core.env.PropertySource<?> p = ctx.getEnvironment().getPropertySources().get("applicationConfigurationProperties");
is the best way to read from application.properties file.
The above ApplicationContextInitializer is registered with Spring as follows -
#SpringBootApplication
public class Application extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
return application.sources(Application.class);
}
public static void main(final String[] args) {
new SpringApplicationBuilder(Application.class).initializers(new SpringPropertiesConfig()).run(args);
}
#Bean
public RestTemplate restTemplate(final RestTemplateBuilder builder) {
return builder.build();
}
}
Related
We use Spring and jOOQ and at present read/write from primary DB. We do have replica DB's and are trying to have non critical reads (like from quartz jobs, pure read api's, etc.) to go to read.
I referred to https://vladmihalcea.com/read-write-read-only-transaction-routing-spring/ and understand that we need a transactional routing layer introduced which would point one way or the other depending on
#Transactional (readonly = true)
However, this doesn't seem to be working in our case, wherein all routing seems to be happening to primary db itself.
Here's the code configurations we use for primary
#Bean(name = "primaryTransactionAwareDataSourceProxy")
public TransactionAwareDataSourceProxy primaryTransactionAwareDataSource(
#Qualifier("primaryDataSource") DataSource primaryDataSource) {
return new TransactionAwareDataSourceProxy(primaryDataSource);
}
#Bean(name = "xyz")
public DataSourceConnectionProvider primaryConnectionProvider(
#Qualifier("primaryTransactionAwareDataSourceProxy") TransactionAwareDataSourceProxy datasource) {
return new DataSourceConnectionProvider(datasource);
}
#Bean(name = "primaryDsl")
#Primary
public DefaultDSLContext primaryDsl(
#Qualifier("primaryConfiguration") DefaultConfiguration configuration) {
return new DefaultDSLContext(configuration);
}
#Bean(name = "primaryConfiguration")
public DefaultConfiguration primaryConfiguration(
#Qualifier("primaryDatabaseProperties") DatabaseProperties props,
#Qualifier("xyz") DataSourceConnectionProvider provider) {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(provider);
jooqConfiguration.set(SQLDialect.MYSQL);
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(<name>)
.withOutput(props.getName())));
jooqConfiguration.set(settings);
return jooqConfiguration;
}
and for replica we have along similar lines
#Bean(name = "replicaTransactionAwareDataSourceProxy")
public TransactionAwareDataSourceProxy replicaTransactionAwareDataSource(
#Qualifier("replicaDataSource") DataSource replicaDataSource) {
return new TransactionAwareDataSourceProxy(replicaDataSource);
}
#Bean(name = "xyz")
public DataSourceConnectionProvider replicaConnectionProvider(
#Qualifier("replicaTransactionAwareDataSourceProxy") TransactionAwareDataSourceProxy datasource) {
return new DataSourceConnectionProvider(datasource);
}
#Bean(name = "replicaDsl")
public DefaultDSLContext replicaDsl(
#Qualifier("replicaConfiguration") DefaultConfiguration configuration) {
return new DefaultDSLContext(configuration);
}
#Bean(name = "replicaConfiguration")
public DefaultConfiguration replicaConfiguration(
#Qualifier("replicaDatabaseProperties") DatabaseProperties props,
#Qualifier("xyz") DataSourceConnectionProvider provider) {
DefaultConfiguration jooqConfiguration = new DefaultConfiguration();
jooqConfiguration.set(provider);
jooqConfiguration.set(SQLDialect.MYSQL);
Settings settings = new Settings()
.withRenderMapping(new RenderMapping()
.withSchemata(new MappedSchema()
.withInput(<name>)
.withOutput(props.getName())));
jooqConfiguration.set(settings);
return jooqConfiguration;
}
The data sources are configured as
#Bean(name = "primaryDatabaseProperties")
#ConfigurationProperties(prefix = "database")
public DatabaseProperties primaryDatabaseProperties() {
return new DatabaseProperties ();
}
#Bean(name = "replicaDatabaseProperties")
#ConfigurationProperties(prefix = "database.replica")
public DatabaseProperties replicaDatabaseProperties() {
return new DatabaseProperties ();
}
#Bean(name = "primaryDataSource")
public DataSource primaryDataSource(
#Qualifier("primaryDatabaseProperties") DatabaseProperties props) {
return dataSource(props);
}
#Bean(name = "replicaDataSource")
public DataSource replicaDataSource(
#Qualifier("replicaDatabaseProperties") DatabaseProperties props) {
return dataSource(props);
}
And transactional routing data source defined as
#Bean
public TransactionRoutingDataSource actualDataSource(
#Qualifier("primaryTransactionAwareDataSourceProxy") DataSource primaryDataSource,
#Qualifier("replicaTransactionAwareDataSourceProxy") DataSource replicaDataSource) {
TransactionRoutingDataSource routingDataSource = new TransactionRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>() {{
put(DataSourceType.READ_WRITE, primaryDataSource);
put(DataSourceType.READ_ONLY, replicaDataSource);
}};
routingDataSource.setTargetDataSources(dataSourceMap);
return routingDataSource;
}
I have an implementation of AbstractRoutingDataSource defined to do the conditional check of if the current transaction is ready only and route to correct datasource accordingly
public class TransactionRoutingDataSource extends AbstractRoutingDataSource {
#Nullable
#Override
protected Object determineCurrentLookupKey() {
return TransactionSynchronizationManager.isCurrentTransactionReadOnly() ?
DataSourceType.READ_ONLY : DataSourceType.READ_WRITE;
}
}
And I use annotations to indicate the necessary routing in the service layer
#Override
#Transactional(readOnly = true)
public <return_type> <method_name>() {}
Any pointers as to what I am missing to have jOOQ route correctly to read db?
I am trying to run test for add data to database using Spring Hibernate. I assigned #Bean for function getSessionFactory in HibernateConfig.java, but when I call again in DAOImp file, I get error Could not autowire. No beans of 'SessionFactory' type found.
HibernateConfig.java
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.huyvt.onlineshopping.dto"})
public class HibernateConfig {
private final static String DATABASE_URL = "jdbc:mysql://localhost:3308/onlineshopping?serverTimezone=UTC";
private final static String DATABASE_DRIVER = "com.mysql.jdbc.Driver";
private final static String DATABASE_DIALECT = "org.hibernate.dialect.H2Dialect";
private final static String DATABASE_USER = "root";
private final static String DATABASE_PASSWORD = "";
#Bean
public DataSource getDataSource(){
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName(DATABASE_DRIVER);
dataSource.setUrl(DATABASE_URL);
dataSource.setUsername(DATABASE_USER);
dataSource.setPassword(DATABASE_PASSWORD);
return dataSource;
}
#Bean
public SessionFactory getSessionFactory(DataSource dataSource){
LocalSessionFactoryBuilder sessionFactoryBuilder = new LocalSessionFactoryBuilder(dataSource);
sessionFactoryBuilder.addProperties(getHibernateProperties());
return sessionFactoryBuilder.buildSessionFactory();
}
private Properties getHibernateProperties(){
Properties properties = new Properties();
properties.put("hibernate.dialect", DATABASE_DIALECT);
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.format_sql", "true");
return properties;
}
#Bean
public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory){
return new HibernateTransactionManager(sessionFactory);
}
}
CategoryDAOImp.java
#Repository("categoryDAO")
public class CategoryDAOImp implements CategoryDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional
public boolean add(Category category) {
try {
//add category to db
System.out.println(category.toString());
sessionFactory.getCurrentSession().persist(category);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
How can I fix it?
In which package is your HibernateConfig class found ?
This
#Bean
public SessionFactory getSessionFactory(DataSource dataSource){
is not being executed.
To confirm, you could do a 'System.out.println("XXX")' like so:
#Bean
public SessionFactory getSessionFactory(DataSource dataSource){
System.out.println("sessionFactory bean is getting created")
...
}
and check if you can see it in your console when you launch your application.
To ensure that it is being picked up, the easiest way is to ensure that you have a #ComponentScan in your root class found here com.huyvt.onlineshopping.
#ComponentScan without arguments tells Spring to scan the current
package and all of its sub-packages.
If you are using Spring Boot, this is automatically added for you when you are using #SpringBootApplication.
Also, in your main method, you can check your created beans like so:
private static ApplicationContext applicationContext;
public static void main(String[] args) {
applicationContext =
new AnnotationConfigApplicationContext(SpringComponentScanApp.class);
for (String beanName : applicationContext.getBeanDefinitionNames()) {
System.out.println(beanName);
}
}
I have project spring-boot using datasource routes in three diferents datasources.
This is my configuration:
#Configuration
#EnableCaching
public class CachingConfiguration extends CachingConfigurerSupport {
#Override
public KeyGenerator keyGenerator() {
return new EnvironmentAwareCacheKeyGenerator();
}
}
--
public class DatabaseContextHolder {
private static final ThreadLocal<DatabaseEnvironment> CONTEXT =
new ThreadLocal<>();
public static void set(DatabaseEnvironment databaseEnvironment) {
CONTEXT.set(databaseEnvironment);
}
public static DatabaseEnvironment getEnvironment() {
return CONTEXT.get();
}
public static void clear() {
CONTEXT.remove();
}
}
--
#Configuration
#EnableJpaRepositories(basePackageClasses = UsuarioRepository.class,
entityManagerFactoryRef = "customerEntityManager",
transactionManagerRef = "customerTransactionManager")
#EnableTransactionManagement
public class DatasourceConfiguration {
#Bean
#ConfigurationProperties(prefix = "spring.ciclocairu.datasource")
public DataSource ciclocairuDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#ConfigurationProperties(prefix = "spring.palmas.datasource")
public DataSource palmasDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#ConfigurationProperties(prefix = "spring.megabike.datasource")
public DataSource megabikeDataSource() {
return DataSourceBuilder.create().build();
}
#Bean
#Primary
public DataSource customerDataSource() {
DataSourceRouter router = new DataSourceRouter();
final HashMap<Object, Object> map = new HashMap<>(3);
map.put(DatabaseEnvironment.CICLOCAIRU, ciclocairuDataSource());
map.put(DatabaseEnvironment.PALMAS, palmasDataSource());
map.put(DatabaseEnvironment.MEGABIKE, megabikeDataSource());
router.setTargetDataSources(map);
return router;
}
#Autowired(required = false)
private PersistenceUnitManager persistenceUnitManager;
#Bean
#Primary
#ConfigurationProperties("spring.jpa")
public JpaProperties customerJpaProperties() {
return new JpaProperties();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean customerEntityManager(
final JpaProperties customerJpaProperties) {
EntityManagerFactoryBuilder builder =
createEntityManagerFactoryBuilder(customerJpaProperties);
return builder.dataSource(customerDataSource()).packages(Users.class)
.persistenceUnit("customerEntityManager").build();
}
#Bean
#Primary
public JpaTransactionManager customerTransactionManager(
#Qualifier("customerEntityManager") final EntityManagerFactory factory) {
return new JpaTransactionManager(factory);
}
private JpaVendorAdapter createJpaVendorAdapter(
JpaProperties jpaProperties) {
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(jpaProperties.isShowSql());
adapter.setDatabase(jpaProperties.getDatabase());
adapter.setDatabasePlatform(jpaProperties.getDatabasePlatform());
//adapter.setGenerateDdl(jpaProperties.isGenerateDdl());
return adapter;
}
private EntityManagerFactoryBuilder createEntityManagerFactoryBuilder(
JpaProperties customerJpaProperties) {
JpaVendorAdapter jpaVendorAdapter =
createJpaVendorAdapter(customerJpaProperties);
return new EntityManagerFactoryBuilder(jpaVendorAdapter,
customerJpaProperties.getProperties(), this.persistenceUnitManager);
}
}
--
public class DataSourceRouter extends AbstractRoutingDataSource {
#Override
protected Object determineCurrentLookupKey() {
if(DatabaseContextHolder.getEnvironment() == null)
DatabaseContextHolder.set(DatabaseEnvironment.CICLOCAIRU);
return DatabaseContextHolder.getEnvironment();
}
}
--
public class EnvironmentAwareCacheKeyGenerator implements KeyGenerator {
#Override
public Object generate(Object target, Method method, Object... params) {
String key = DatabaseContextHolder.getEnvironment().name() + "-" + (
method == null ? "" : method.getName() + "-") + StringUtils
.collectionToDelimitedString(Arrays.asList(params), "-");
return key;
}
}
I set datasource using
DatabaseContextHolder.set(DatabaseEnvironment.CICLOCAIRU);
Go to problem:
For example, two users in diferents datasources: 1 and 2
if one user using datasource 1, and send a request,
The other user that using datasource 2,
yours next request , instead of datasource 2, this get datasource 1. I think that this ThreadLocal<DatabaseEnvironment> CONTEXT =
new ThreadLocal<>(); was exclusive for request, But this does not seem to be so.
Iam sorry if this not be clear.
In realy, i need that DataSurceRouter were exclusive for each request, and an request not intefer in another.
I wrong about i think of DatasourceRouter or my code is bad ?
The issue probably occurs because of server thread pool: you have a given number of threads, and each request is served rolling among them.
When the server recycles a thread, the thread local variable has that value already set from the previous cycle, so you need to flush that value after each request, leaving the thread in a clean state.
I need helps.
I want to create a batch application which the scenario is
Read data from database and then write it to text file. [ Consider this as the first step]
When the first step is done, the second step is writing a ctl file which contains the writeCount of the first step.
My approach is that I create a stepExecutionListener to put the jobId context to JobExecutionContext.
So, In ItemReader of second step, I can read from the database. But I don't know how to get the jobExecutionId so that I can query the Mysql to get the right record.
Here is the code
public class WriteDataCtlFile {
private static final Logger log = LoggerFactory.getLogger(WriteDataCtlFile.class);
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Bean
public Step writeCtlFile(ItemReader<JobContext> ctlReader,
ItemProcessor<JobContext, CtlFile> ctlProcessor,
ItemWriter<CtlFile> ctlWriter){
return stepBuilderFactory.get("writeCtlFile")
.<JobContext, CtlFile>chunk(100)
.reader(ctlReader)
.processor(ctlProcessor)
.writer(ctlWriter)
.build();
}
#JobScope
#Bean
public ItemReader<JobContext> ctlReader(DataSource dataSource, JobContextMapper jobContextMapper) {
JdbcCursorItemReader<JobContext> reader = new JdbcCursorItemReader<>();
reader.setDataSource(dataSource);
reader.setSql("SELECT short_context FROM BATCH_JOB_EXECUTION_CONTEXT WHERE JOB_EXECUTION_ID = ?");
// THIS IS WHERE I WANT TO GET jobId
reader.setPreparedStatementSetter(new JobIdPrepareStatement(jobId));
reader.setRowMapper(jobContextMapper);
return reader;
}
#Bean
public ItemProcessor<JobContext, CtlFile> ctlProcessor(){
return new ItemProcessor<JobContext, CtlFile>() {
#Override
public CtlFile process(JobContext jobContext) throws Exception {
return new CtlFile(jobContext.getShort_context());
}
};
}
#Bean
public FlatFileItemWriter<CtlFile> ctlWriter(){
FlatFileItemWriter<CtlFile> flatFileItemWriter = new FlatFileItemWriter<>();
flatFileItemWriter.setResource(new FileSystemResource("C:\\Users\\wathanyu.phromma\\data-output.ctl"));
flatFileItemWriter.setLineAggregator(new LineAggregator<CtlFile>() {
#Override
public String aggregate(CtlFile ctlFile) {
Gson gson = new Gson();
Map<String, Object> map = gson.fromJson(ctlFile.getWrittenRecordsCount(), Map.class);
return String.valueOf(map.get("writeCount"));
}
});
return flatFileItemWriter;
}
}
public class WriteDataTxtFile {
private static final Logger log = LoggerFactory.getLogger(WriteDataTxtFile.class);
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Bean
public Step writeTxtFile(
ItemReader<Account> reader,
ItemProcessor<Account, Account> processor,
ItemWriter<Account> writer){
return stepBuilderFactory.get("writeTxtFile")
.<Account, Account>chunk(2)
.reader(reader)
.processor(processor)
.writer(writer)
.listener(new WriteDataTxtStepListener())
.build();
}
#Bean
#StepScope
public JdbcCursorItemReader<Account> reader(DataSource dataSource, AccountMapper accountMapper) {
log.info("test");
JdbcCursorItemReader<Account> reader = new JdbcCursorItemReader<>();
reader.setDataSource(dataSource);
reader.setSql("SELECT * FROM account");
reader.setRowMapper(accountMapper);
return reader;
}
#Bean
public ItemProcessor<Account, Account> processor(){
return new ItemProcessor<Account, Account>() {
#Override
public Account process(Account account) throws Exception {
return account;
}
};
}
#Bean
public FlatFileItemWriter<Account> writer(){
FlatFileItemWriter<Account> flatFileItemWriter = new FlatFileItemWriter<>();
flatFileItemWriter.setResource(new FileSystemResource("C:\\Users\\wathanyu.phromma\\data-output.txt"));
flatFileItemWriter.setLineAggregator(new DelimitedLineAggregator<Account>(){{
setDelimiter("|");
setFieldExtractor(new BeanWrapperFieldExtractor<Account>(){{
setNames(new String[]{ "id", "accountId", "accountName","createdAt", "updatedAt"});
}});
}});
return flatFileItemWriter;
}
public class WriteDataTxtStepListener implements StepExecutionListener {
private static final Logger log = LoggerFactory.getLogger(WriteDataTxtStepListener.class);
#Override
public void beforeStep(StepExecution stepExecution) {
Date date = new Date();
String currentDate = new SimpleDateFormat("YYYY-mm-dd").format(date);
stepExecution.getJobExecution().getExecutionContext().put("jobId", stepExecution.getJobExecutionId());
stepExecution.getJobExecution().getExecutionContext().put("date", currentDate);
log.info("JobId = " + stepExecution.getJobExecutionId());
log.info("Before Step Count = " + stepExecution.getWriteCount());
}
#Override
public ExitStatus afterStep(StepExecution stepExecution) {
stepExecution.getJobExecution().getExecutionContext().put("writeCount", stepExecution.getWriteCount());
log.info("After Step Count = " + stepExecution.getWriteCount());
log.info("ExitStatus = " + stepExecution.getExitStatus().getExitCode());
return stepExecution.getExitStatus();
}
}
public class WriteDataToFlatFile {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Bean
public Job readFromApi(Step writeTxtFile, Step writeCtlFile){
return jobBuilderFactory.get("readFromApiToFlatFile")
.incrementer(new RunIdIncrementer())
.start(writeTxtFile)
.next(writeCtlFile)
.build();
}
#Bean
public DataSource dataSource(){
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/xxxx?useSSL=false");
dataSource.setUsername("xxxx");
dataSource.setPassword("xxxx");
return dataSource;
}
}
To get data from the job execution context in the reader of your second step, you can inject the value as a parameter in your bean definition method like this:
#JobScope
#Bean
public ItemReader<JobContext> ctlReader(DataSource dataSource, JobContextMapper jobContextMapper, #Value("#{jobExecutionContext['jobId']}") int jobId) {
// use jobId
}
Hope this helps.
I have a Vaadin web application with UI class like this:
#SuppressWarnings("serial")
#Theme("mytheme")
public class LogsUI extends UI {
LogsView logsViewer = new LogsView();
#WebServlet(value = "/*", asyncSupported = true)
#VaadinServletConfiguration(productionMode = false, ui = LogsUI.class)
public static class Servlet extends VaadinServlet {
}
#Override
protected void init(VaadinRequest request) {
Panel panel = new Panel();
panel.setContent(logsViewer);
panel.setSizeFull();
setContent(panel);
}
}
As u can see i add use setContent to add LogsView class which is a view - it is a fragment of declaration:
#SuppressWarnings("serial")
public class LogsView extends CustomComponent implements View {
//some variables, buttons, components etc
ProcessDao processDao;
//sample method
void sampleMethod(){
processDao = new ProcesDao;
processDao.getAllprocesses(); //just sample, no matter about logic
}
}
My ProcessDao class:
public class ProcessDao {
#Autowired
ApplicationConfiguration applicationConfiguration;
public ProcessDao() {
}
public List<ProcessEntity> getAllProcess(){
System.out.println("TEST:" + applicationConfiguration);
//entity manager and other stuffs
return processList;
}
}
As u can see i did System.out.println() to check if im getting applicationConfiguration object. Im getting null. This is main problem.
this is my ApplicationConfiguration class:
#Configuration
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.sample.project"})
#PropertySource({"classpath:jpa.postgresql.properties", "classpath:hibernate.properties"})
#EnableJpaRepositories(basePackages = {"com.sample.project.repo"})
public class ApplicationConfiguration extends WebMvcConfigurerAdapter {
#Value("${javax.persistence.jdbc.driver}")
private String driverClassName;
#Value("${javax.persistence.jdbc.url}")
private String databaseUrl;
#Value("${javax.persistence.jdbc.user}")
private String databaseUser;
#Value("${javax.persistence.jdbc.password}")
private String databasePassword;
#Value("${hibernate.dialect}")
private String dialect;
#Value("${hibernate.show_sql}")
private boolean showSQL;
#Value("${hibernate.hbm2ddl.auto}")
private String hbm2ddlAuto;
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
#PersistenceContext
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean();
entityManagerFactoryBean.setDataSource(dataSource());
entityManagerFactoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
entityManagerFactoryBean.setJpaProperties(hibernateJPAProperties());
entityManagerFactoryBean.setPackagesToScan("com.sample.project");
return entityManagerFactoryBean;
}
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(driverClassName);
dataSource.setUrl(databaseUrl);
dataSource.setUsername(databaseUser);
dataSource.setPassword(databasePassword);
return dataSource;
}
public Properties hibernateJPAProperties() {
Properties properties = new Properties();
properties.put("hibernate.dialect", dialect);
properties.put("hibernate.show_sql", showSQL);
properties.put("hibernate.hbm2ddl.auto", hbm2ddlAuto);
return properties;
}
#Bean
public JpaTransactionManager transactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
#Bean
public FinancialProcessEntityDao financialProcessEntityDao() {
FinancialProcessEntityDao dao = new FinancialProcessEntityDao();
return dao;
}
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
Am i something missing? How to properly integrate my Vaadin app with Spring?
You should try this:
processDao = WebApplicationContextUtils.getRequiredWebApplicationContext(
VaadinServlet.getCurrent().getServletContext()).getBean(IProcessDao.class);
You can find some description here: link