How to get JobExecutionContext from a Partitioner - spring

I have a InitTasklet that runs before an Master/Slave with partitioner strategy. In this initial tasklet I access the database and get a list with ids and put into context:
chunkContext.getStepContext().getStepExecution().getJobExecution()
.getExecutionContext().put("listaBancos", lista);
I need to access this list in my Partitioner
I tried this way with no success: the method beforeJob is never executed.
public class BancoPartitioner extends JobExecutionListenerSupport ...
#Override
public void beforeJob(JobExecution jobExecution) {
this.context = jobExecution.getExecutionContext();
super.beforeJob(jobExecution);
}
I tried to autowired the stepExecution this way:
#Value("#{stepExecution}")
private StepExecution stepExecution;
but I get an exception:
Error creating bean with name 'bancoPartitioner': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.batch.core.StepExecution .....stepExecution; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 0): Field or property 'stepExecution' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext'.
Is there any way to access the Execution context from a Partitioner?

It works with scope="step" in the declaration of Partitioner Bean, as bellabax explained.

Related

Bean instantiation via factory method failed

I am getting below error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'fileStorageServiceBean' defined in com.primesolutions.fileupload.settings.FileStorageProperties: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.primesolutions.fileupload.service.FileStorageService]: Factory method 'fileStorageServiceBean' threw exception; nested exception is java.lang.StackOverflowError
#ConfigurationProperties(prefix = "file")
public class FileStorageProperties {
private String uploadDir;
#Bean
public FileStorageService fileStorageServiceBean() throws Exception{
return new FileOnDiskStorageService(); // some random name; don't exist
}
public String getUploadDir() {
return uploadDir;
}
public void setUploadDir(String uploadDir) {
this.uploadDir = uploadDir;
}
}
Your method:
public FileStorageService fileStorageServiceBean() throws Exception{
return fileStorageServiceBean();
}
Is a recursive function. Which causes the stackOverflowError.
You get a java.lang.StackOverflowError because the method fileStorageServiceBean() is calling itself and that will result in an infinite loop. That code part can never end in this situation.
It could/should be something like:
#Bean
public FileStorageService fileStorageServiceBean() throws Exception{
return new FileOnDiskStorageService(); // some random name; don't exist
}
If you use a good IDE it will warn you about this. It's a good advice to always use a good IDE for Java and read the warnings. Also installing the plugins like SonarQube, Findbugs is really helpful to prevent for code issues.
Also the errors stacktrace will give a line number and some info where in the code the error occurs.

how to config mybatis in springboot

I have two config here:
#Configuration
public class DataConfig {
#Value("${datasource.jdbcUrl}")
private String jdbcUrl;
#Value("${datasource.username}")
private String username;
#Value("${datasource.password}")
private String password;
#Value("${datasource.driverClassName:com.mysql.jdbc.Driver}")
private String driverClassName;
#Value("${datasource.initialSize:20}")
private int initialSize;
#Value("${datasource.maxActive:30}")
private int maxActive;
#Value("${datasource.minIdle:20}")
private int minIdle;
#Value("${datasource.transactionTimeoutS:30}")
private int transactionTimeoutS;
#Value("${datasource.basePackage:com.tg.ms.mapper}")
private String basePackage;
#Value("${datasource.mapperLocations}")
private String mapperLocations;
#Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setMaxWait(maxWait);
ds.setValidationQuery(validationQuery);
ds.setRemoveAbandoned(removeAbandoned);
ds.setRemoveAbandonedTimeout(removeAbandonedTimeout);
ds.setTestWhileIdle(testWhileIdle);
ds.setTestOnReturn(testOnReturn);
ds.setTestOnBorrow(testOnBorrow);
ds.setMinIdle(minIdle);
return ds;
}
#Bean
public SqlSessionFactory sqlSessionFactoryBean() throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource());
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sqlSessionFactoryBean.setMapperLocations(resolver.getResources("classpath:/mybatis/*.xml"));
return sqlSessionFactoryBean.getObject();
}
---------- Another Config -------------
#Configuration
#AutoConfigureAfter(DataBaseConfig.class)
public class MapperScannerConfig {
#Value("${datasource.basePackage:com.tg.ms.mapper}")
private String basePackage;
#Bean
public MapperScannerConfigurer BPMapperScannerConfigurer() {
System.out.println("mapper--1.----******----"+basePackage+"----*******");
MapperScannerConfigurer mapperScannerConfigurer = new MapperScannerConfigurer();
mapperScannerConfigurer.setBasePackage("com.tg.mapper");
mapperScannerConfigurer.setSqlSessionFactoryBeanName("sqlSessionFactoryBean");
return mapperScannerConfigurer;
}
}
Can I put#Bean public MapperScannerConfigurer BPMapperScannerConfigurer() into DataConfig? I try but print:
Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'testController': Unsatisfied dependency expressed through field 'testMapper'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'testMapper' defined in file [/Users/twogoods/codesource/mainetset/target/classes/com/tg/mapper/TestMapper.class]: Cannot resolve reference to bean 'sqlSessionFactoryBean' while setting bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactoryBean' defined in class path resource [com/tg/config/DataConfig.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactoryBean' threw exception; nested exception is java.lang.NullPointerException
MapperScannerConfig init earlier than DataConfig, I get it from print log,#Value("${datasource.basePackage:com.tg.ms.mapper}") private String basePackage;can not get value(in DataConfig can get),I use #AutoConfigureAfter is useless,MapperScannerConfig is also eariler, I can not config mapper basePackage
log:Cannot enhance #Configuration bean definition 'BPMapperScannerConfigurer' since its singleton instance has been created too early. The typical cause is a non-static #Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.
I got the same problem. MapperScannerConfigurer is initialized too early in spring framework and ,i think it causes the annotation #AutoConfigureAfter become useless.
So i solve it like : avoid the use of MapperScannerConfigurer:
two ways:
just use #MapperScan("com.a.b.package")
use annotation #org.apache.ibatis.annotations.Mapper in your mybatis mapper interface.

Spring - Autowire fails when adding an aspect-backed annotation to overridden method

I have an authentication service implementing org.springframework.security.core.userdetails.UserDetailsService and defined as:
#Service
public class AuthService implements UserDetailsService {
// Autowires ..
#Override
//#Logged(successMessage = "User %s logged in")
public UserDetails loadUserByUsername(String username) { .. }
}
It is autowired into an extension of WebSecurityConfigurerAdapter and used to configure authentication:
// Annotations ...
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthService authService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
auth.userDetailsService(authService).passwordEncoder(encoder);
}
// Other security config stuff ...
}
And last, I have created a custom annotation called #Logged, that is picked up by an aspect that applies around advice to the annotated method and performs some logging logic. Lets just say that if you pass only one argument to it, it will log successful returns.
Applying the #Logged annotation to the overriden AuthService.loadUserByUsername method causes the application to crash on startup, displaying the message about not being able to autowire AuthService into the SecurityConfig. Everything works flawlessly if I don't put the annotation to that overriden method - authentication works (complete with autowiring) and logging annotation works in other parts of the system.
Question
Why is this happening and can it be fixed?
I would really like to log that exact method using my fancy logging anotation.
Thanks :)
Technical details
Spring 4 with Boot, Jetty 9
Stack trace (part of):
2014-09-22 12:41:05 WARN AbstractLifeCycle - FAILED org.springframework.boot.context.embedded.jetty.ServletContextInitializerConfiguration$InitializerListener#8bb473: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire method: public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.setFilterChainProxySecurityConfigurer(org.springframework.security.config.annotation.ObjectPostProcessor,java.util.List) throws java.lang.Exception; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.bluepixelflag.services.AuthService com.bluepixelflag.config.SecurityConfig.authService; nested exception is java.lang.IllegalArgumentException: Can not set com.bluepixelflag.services.AuthService field com.bluepixelflag.config.SecurityConfig.authService to com.sun.proxy.$Proxy90
Spring is using a proxy to add aspects to AuthService. Without the annotation it would just use a simple class.
Change
private AuthService authService;
to
private UserDetailsService authService;
and it ought to work. Or, use cglib proxies instead of JDK dynamic proxies.
Aside: the point of using aspects for logging is to try to avoid one line of code per logging call. If you use an aspect annotation for every method call you want logged, you haven't saved any complexity (in fact you've increased it), and might as well just call a logger in code.

#Override and #Transactional annotations

I use jpa, eclispelink and spring 3. I have UserDAO interface:
public interface UserDAO {
public void saveUser(User user);
}
and implementing class :
#Service
#Transactional
public class UserDAOImpl implements UserDAO{
#PersistenceContext
EntityManager em;
#Override
public void saveUser(User user) {
em.persist(user);
}
When I start app I have got error:
HTTP Status 500 - Servlet.init() for servlet appServlet threw exception<br>
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cartController': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: foo.endpoints.UserEndpoint foo.controller.CartController.userEndpoint; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userEndpoint': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: foo.dao.UserDAOImpl foo.endpoints.UserEndpoint.userDAO; nested exception is java.lang.IllegalArgumentException: Can not set foo.dao.UserDAOImpl field foo.endpoints.UserEndpoint.userDAO to com.sun.proxy.$Proxy16
org.springframework.beans.factory.BeanCreationException: Could not autowire field: foo.endpoints.UserEndpoint foo.controller.CartController.userEndpoint; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userEndpoint': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: foo.dao.UserDAOImpl foo.endpoints.UserEndpoint.userDAO; nested exception is java.lang.IllegalArgumentException: Can not set foo.dao.UserDAOImpl field foo.endpoints.UserEndpoint.userDAO to com.sun.proxy.$Proxy16
but if I don't implement interface:
#Service
#Transactional
public class UserDAOImpl {
#PersistenceContext
EntityManager em;
public void saveUser(User user) {
em.persist(user);
}
everything work ok. I don't understand it. Maybe it is something with #Override method? Thanks
If you define an interface for your bean, then you must inject an instance of the interface, and not an instance of the concrete class:
#Autowired
private UserDAO userDAO;
and not
#Autowired
private UserDAOImpl userDAOImpl;
Because the actual bean instance is a JDK dynamic proxy which implements the interface and calls your implementation. It's not an instance of UserDAOImpl.

Spring Autowiring failing when using Cobertura

When I run Cobertura, it causes the following Spring autowiring error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userResource': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.dnb.components.storage.service.UserService com.dnb.components.storage.rest.resource.UserResource.userService; nested exception is java.lang.IllegalArgumentException: Can not set com.dnb.components.storage.service.UserService field com.dnb.components.storage.rest.resource.UserResource.userService to com.sun.proxy.$Proxy56 at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:287)
As suggested in other related posts, I tried forcing Spring to use CGLIB by changing "proxyTargetClass=true", but this results in a different error:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userResource': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.dnb.components.storage.service.UserService com.dnb.components.storage.rest.resource.UserResource.userService; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userService': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: com.dnb.components.storage.repository.UserRepository com.dnb.components.storage.service.UserService.repository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Post-processing of the FactoryBean's object failed; nested exception is org.springframework.aop.framework.AopConfigException: Could not generate CGLIB subclass of class [class com.sun.proxy.$Proxy54]: Common causes of this problem include using a final class or a non-visible class; nested exception is java.lang.IllegalArgumentException: Cannot subclass final class class com.sun.proxy.$Proxy54
This is what the Repository class looks like:
#Transactional
public interface UserRepository extends CrudRepository<User, Long> {
public User findByCrmId(String crmIdId);
}
Here is the service that gets injected with UserRepository:
#Service
#Transactional
public class UserService extends TraceablePersistenceService<User, UserRepository> {
#Autowired
UserRepository repository;
#Transactional
public Iterable<User> findAll() {
return repository.findAll();
}
public User findOne(Long id) {
return repository.findOne(id);
}
}
Our configuration is in
#Configuration
#EnableTransactionManagement(proxyTargetClass=true)
#EnableJpaRepositories(basePackages = {"com.dnb.components.storage.repository"})
#Profile("inmemory")
public class InMemoryStandaloneStorageConfig extends BasicJpaStorageConfig {
....
(omitted for brevity)
UserResource.java:
#Component
#Path(UserResource.uri)
public class UserResource extends AbstractResource {
public final static String uri = BASE_URI + "/users";
#Override
public String getURI() {
return BASE_URI + uri;
}
#Autowired
private UserService userService;
...
It seems that the Spring Data JPA generated Repository class cannot be proxied either way without screwing up the auto-wiring.
Is there a fix for this? Is it even a good idea to annotate Repository methods with #Transactional? Should the annotation be at the service level only?
usually, we do not inject concrete classes but we inject interfaces.
this is my suggestion.
a. refactor UserService to UserServiceImpl class
b. create UserService interface
c. UserServiceImpl implements UserService
d. add "findAll" and "findOne" method declaration to UserService interface

Resources