How to mock task:executor in Spring - java

#Component
public class SampleApplication {
private static final Logger LOGGER = Logger.Factory.getLogger();
private KafkaProducer<String, String> producer = null;
public SampleApplication() {}
#Async(value = "audit-task-executor")
public void sendMessageToExternalKafka(String casterMessage) throws IOException {}
}
In spring bean.xml
<task:executor id="audit-task-executor"
pool-size="1"
queue-capacity="1"
rejection-policy="DISCARD_OLDEST"/>
I want to write a test to mock it, but not able to do it. Its throwing following exception.
Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/springframework/objenesis/SpringObjenesis
My test configuration:
#Bean(name = "producerExt")
FactoryBean sampleApplication() {
return new AbstractFactoryBean() {
#Override
public Class getObjectType() {
return SampleApplication.class;
}
#Override
protected SampleApplication createInstance() {
return mock(SampleApplication.class);
}
};
}
#Bean(name = "audit-task-executor")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
return mock(ThreadPoolTaskExecutor.class);
}
Implemented FactoryBean to avoid invocation of #PostConstruct

Related

Access command line arguments in springboot in thread

I run my spring boot application with
mvn spring-boot:run -Dspring-boot.run.arguments="test1, test2, test3"
I need this 3 arguments in my runnable. How can i access them in my Compressor runnable class? It prints null.
#Configuration
public class MultiThreadConfig {
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
return new CommandLineRunner() {
public void run(String[] args) throws Exception {
executor.execute(new Compressor(args));
}
};
}
}
public class Compressor implements Runnable {
#Autowired
ApplicationArguments appArgs;
String[] args;
// Constructor
public Compressor(String[] args) {
//Initialization of atributes
}
#Override
public void run() {
System.out.println("COMPRESSOR YO");
System.out.println(Arrays.toString(args));
System.out.println(appArgs);
}
}
As Jesper pointed out you are creating the Compressor object by yourself using new keyword so the ApplicationArguments will not be autowired as this instance of Compressor is not managed by Spring. The solution is to create a bean for Compressor object and let it be managed by Spring. For example :
#Configuration
public class MultiThreadConfig {
#Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
#Bean
public Compressor compressor(ApplicationArguments applicationArguments) {
return Compressor(applicationArguments);
}
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor, Compressor compressor) {
return new CommandLineRunner() {
public void run(String[] args) throws Exception {
executor.execute(compressor);
}
};
}
}
and
public class Compressor implements Runnable {
private final ApplicationArguments appArgs;
private final String[] args;
#Autowired
public Compressor(ApplicationArguments applicationArguments) {
appArgs = applicationArguments;
args = applicationArguments.getSourceArgs();
}
#Override
public void run() {
System.out.println("COMPRESSOR YO");
System.out.println(Arrays.toString(args));
}
}
Note here that I am using constructor injection instead of field injections which is typically better option.
If you do not want to crate a bean in configuration you could also mark Compressor with Spring stereotype :
#Component
public class Compressor implements Runnable {
private final ApplicationArguments appArgs;
private final String[] args;
public Compressor(ApplicationArguments applicationArguments) {
appArgs = applicationArguments;
args = applicationArguments.getSourceArgs();
}
//...
}
and use instance of it in your configuration like shown above :
#Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor, Compressor compressor) {
//...
}

Multiple configuration properties in spring boot #Autowired one of the properties are null

I am new to spring, I have following boot application classes. I am trying to connect to AWS SQS from Spring boot application. The code is as below:
#SpringBootApplication
#EnableConfigurationProperties ({ApplicationProperties.class, AwsProperties.class})
public class Application{
private static final Logger logger = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) throws IOException {
SpringApplication.run(Application.class, args);
}
}
ApplicationProperties.java
#Configuration
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix="midb")
public class ApplicationProperties {
private String keyStore;
private String keyStorePassword;
// getter and setters
}
AwsProperties.java
#Configuration
#PropertySource("classpath:application.properties")
#ConfigurationProperties(prefix="aws")
public class AwsProperties {
private String sqsEndpoint;
private String accessKey;
private String secretKey;
// getters and setters
}
#Configuration
#EnableJms
#EnableConfigurationProperties(AwsProperties.class)
public class JmsConfig {
private static final Logger logger = LoggerFactory.getLogger(JmsConfig.class);
#Autowired
private AwsProperties awsProperties;
#Autowired
private SQSListener sqsListener;
#PostConstruct
public void init() {
//System.out.println("================== " + awsProperties.toString() + "==================");// End point:"+endpoint);
}
#Bean
public AmazonSQSClient createSQSClient() {
AmazonSQSClient amazonSQSClient = new AmazonSQSClient(new BasicAWSCredentials(awsProperties.getAccessKey(), awsProperties.getSecretKey()));
amazonSQSClient.setEndpoint(awsProperties.getSqsEndpoint());
amazonSQSClient.createQueue(awsProperties.getSqsQueueName());
return amazonSQSClient;
}
#Bean
public DefaultMessageListenerContainer jmsListenerContainer() {
SQSConnectionFactory sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(new DefaultAWSCredentialsProviderChain())
.withEndpoint(awsProperties.getSqsEndpoint()).withAWSCredentialsProvider(awsCredentialsProvider)
.withNumberOfMessagesToPrefetch(10).build();
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setConnectionFactory(sqsConnectionFactory);
dmlc.setDestinationName(awsProperties.getSqsQueueName());
dmlc.setMessageListener(sqsListener);
return dmlc;
}
#Bean
public JmsTemplate createJMSTemplate() {
SQSConnectionFactory sqsConnectionFactory = SQSConnectionFactory.builder()
.withAWSCredentialsProvider(awsCredentialsProvider).withEndpoint(awsProperties.getSqsEndpoint())
.withNumberOfMessagesToPrefetch(10).build();
JmsTemplate jmsTemplate = new JmsTemplate(sqsConnectionFactory);
jmsTemplate.setDefaultDestinationName(awsProperties.getSqsQueueName());
jmsTemplate.setDeliveryPersistent(false);
return jmsTemplate;
}
private final AWSCredentialsProvider awsCredentialsProvider = new AWSCredentialsProvider() {
#Override
public AWSCredentials getCredentials() {
return new BasicAWSCredentials(awsProperties.getAccessKey(), awsProperties.getSecretKey());
}
#Override
public void refresh() {
}
};
}
When Maven builds, I get the following error:
Caused by: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'createSQSClient' defined in class path
resource [io/bigbear/midb/sqs/JmsConfig.class]: Bean instantiation via
factory method failed; nested exception is
org.springframework.beans.BeanInstantiationException: Failed to
instantiate [com.amazonaws.services.sqs.AmazonSQSClient]: Factory
method 'createSQSClient' threw exception; nested exception is
java.lang.IllegalArgumentException: Access key cannot be null.
I'm not sure but it seems your awsProperties.getAccessKey() returns null.

Unable to autowire service in extended java class, throwing NullPointerException

I'm trying to Autowire service inside java class which is extended from TimerTask. This Returning null value while trying to return service in java class. This is the class in which I'm trying to Autowire service:
#Component
public class Task extends TimerTask
{
#Autowired
FileDetailsService fileDetailsService;
int count = 1;
#Override
public void run()
{
fileDetailsService.updateProcessingStatus(fileAudit);
}
Configuration classes: There is no web.xml.....I have configured in java using spring 4
//DataConfig.java
#Configuration
#MapperScan("com.fileC.mapper")
public class DataConfig {
#Bean
public DataSource dataSource() {
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
dataSource.setDriverClass(oracle.jdbc.driver.OracleDriver.class);
dataSource.setUsername("username");
dataSource.setUrl("jdbc***thin**sample **url");
dataSource.setPassword("****");
return dataSource;
}
#Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setTypeAliasesPackage("com.fileC.model");
return sessionFactory;
}
//ApplConfig.java
#Configuration
#ComponentScan(basePackages="com.filec")
public class ApplConfig {
#Bean
public CommonsMultipartResolver multipartResolver(){
CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
commonsMultipartResolver.setDefaultEncoding("utf-8");
commonsMultipartResolver.setMaxUploadSize(50000000);
return commonsMultipartResolver;
}
}
I'm using Spring4, java1.8, ibatis, SQL database.
Here is the service class,
#Service("fileDetailsService")
#Transactional
public class FileDetailsServiceImpl implements FileDetailsService{
private static Logger logger = LoggerFactory.getLogger(FileDetailsServiceImpl.class);
#Autowired
FileDetailsMapper fileDetailsMapper;
#Override
public void insertFileInfo(Details details){
fileDetailsMapper.insertDetails(details);
}
Here is the exception details,
fileAuditMapper>>>>null
Exception in thread "Timer-9" java.lang.NullPointerException at com.filecompare.service.Task.run(Task.java:117)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Please, let me know if I need to add something in config.

How to make Spring #Transactional to work in junit test

I try to make my test to work with Spring #Transactional annotation.
#ContextConfiguration(classes = SomeTest.SomeTestSpringConfig.class)
#RunWith(SpringJUnit4ClassRunner.class)
public class SomeTest {
#Autowired
MyBean some;
#Autowired
PlatformTransactionManager transactionManager;
#Test
public void testSpring() throws Exception {
some.method();
assertTrue(some.isTransactionalWorks);
}
#EnableAspectJAutoProxy(proxyTargetClass = true)
#EnableLoadTimeWeaving
#EnableTransactionManagement(mode = AdviceMode.ASPECTJ)
#TransactionConfiguration
static class SomeTestSpringConfig {
#Bean
PlatformTransactionManager transactionManager() {
return new MyTransactionManager(dataSource());
}
#Bean
MyBean some() {
return new MyBean();
}
#Bean
DataSource dataSource() {
return new SimpleDriverDataSource(Driver.load(), "jdbc:h2:mem:unit-test");
}
}
}
class MyBean {
#Autowired
DataSource dataSource;
public boolean isTransactionalWorks;
#Transactional
private void someInTransaction() {
try {
dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
System.out.println("I should be in transaction");
}
public void method() {
someInTransaction();
}
}
class MyTransactionManager implements PlatformTransactionManager, InitializingBean {
private final DataSourceTransactionManager base = new DataSourceTransactionManager();
#Autowired
MyBean some;
public MyTransactionManager(DataSource datasource) {
base.setDataSource(datasource);
}
#Override
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
some.isTransactionalWorks = true;
return base.getTransaction(definition);
}
#Override
public void commit(TransactionStatus status) throws TransactionException {
base.commit(status);
}
#Override
public void rollback(TransactionStatus status) throws TransactionException {
base.rollback(status);
}
#Override
public void afterPropertiesSet() throws Exception {
base.afterPropertiesSet();
}
}
Also I added -javaagent:D:/libs/spring-instrument-4.1.7.RELEASE.jar to VM options for this test.
But it always fails. What did I miss?
Please check this link, i think it is the similar problem u are facing.
How to configure AspectJ with Load Time Weaving without Interface
In this link he has asked to provide both aspectjweaver.jar and spring-instrument.jar in vm argument.
Good to know it worked. :)

FactoryBeanNotInitializedException: Cannot determine target class for proxy

I want to setup an object pool in my spring application with annotation only.
I started out with this example taken from Spring docs: http://docs.spring.io/spring/docs/2.5.x/reference/aop-api.html#aop-ts-pool.
Here is how I translate the XML configuration:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class SpringObjectPoolTest {
public static void main(String[] args) throws Exception {
context = new SpringApplicationBuilder(SpringObjectPoolTest.class) //
.addCommandLineProperties(false) //
.web(false) //
.headless(false) //
.registerShutdownHook(true) //
.application() //
.run();
context.getBean(SpringObjectPoolTest.class).go();
}
#Resource(name = "pfb")
private FactoryBean<MyTask> pool;
#Resource(name="pool")
private TargetSource targetSource;
private static ConfigurableApplicationContext context;
#Bean(name = "task")
#Scope("prototype")
public MyTask createNewTask() {
return new MyTask();
}
#Bean(name = "pool")
public CommonsPoolTargetSource setupObjectPool() {
CommonsPoolTargetSource pc = new CommonsPoolTargetSource();
pc.setMaxSize(25);
pc.setTargetBeanName("task");
return pc;
}
#Bean(name = "pfb")
public ProxyFactoryBean createProxyFactoryBean() {
ProxyFactoryBean pfb = new ProxyFactoryBean();
pfb.setTargetSource(targetSource);
return pfb;
}
private void go() {
try {
pool.getObject().speak();
} catch (Exception e) {
e.printStackTrace();
}
}
}
However I get this exception:
org.springframework.beans.factory.BeanCurrentlyInCreationException:
Error creating bean with name 'pfb':
org.springframework.beans.factory.FactoryBeanNotInitializedException:
Cannot determine target class for proxy
You are a bit over engineering this. Spring already knows how to inject a proxied MyTask, there is no need to have a FactoryBean<MyTask> or to call getObject() on the pool. In "pooledTask" below Spring knows that by injecting a ProxyFactoryBean ("pfb") it will actually inject the instance that factory bean creates, not the factory bean itself. Here's how I'd do it:
#Configuration
#EnableAutoConfiguration
#ComponentScan
public class SpringObjectPoolTest {
public static void main(String[] args) throws Exception {
context = new SpringApplicationBuilder(SpringObjectPoolTest.class) //
.addCommandLineProperties(false) //
.web(false) //
.headless(false) //
.registerShutdownHook(true) //
.application() //
.run();
context.getBean(SpringObjectPoolTest.class).go();
}
private static ConfigurableApplicationContext context;
#Resource(name = "pfb")
private MyTask pooledTask;
#Resource(name="pool")
private CommonsPoolTargetSource targetSource;
#Bean(name = "task")
#Scope("prototype")
public MyTask createNewTask() {
return new MyTask();
}
#Bean(name = "pool")
public CommonsPoolTargetSource setupObjectPool() {
CommonsPoolTargetSource pc = new CommonsPoolTargetSource();
pc.setMaxSize(25);
pc.setTargetBeanName("task");
return pc;
}
#Bean(name = "pfb")
public ProxyFactoryBean createProxyFactoryBean() {
ProxyFactoryBean pfb = new ProxyFactoryBean();
pfb.setTargetSource(setupObjectPool());
return pfb;
}
private void go() {
try {
pooledTask.speak();
// getting another object from pool
MyTask someOtherTask = (MyTask) targetSource.getTarget();
// returning the object to the pool
targetSource.releaseTarget(someOtherTask);
} catch (Exception e) {
e.printStackTrace();
}
}
}

Categories