WebSocketConfigurer and #Scheduled() are not work well in an application - spring

I can either use websocket that configure with WebSocketConfigurer or use #Scheduled() to schedule task without any problem.
However, java does not compile when i use both of them.
#Scheduled() annotation may crash with
org.springframework.web.socket.config.annotation.WebSocketConfigurationSupport$NoOpScheduler.scheduleAtFixedRate()
java.lang.IllegalStateException: Unexpected use of scheduler.
at org.springframework.web.socket.config.annotation.WebSocketConfigurationSupport$NoOpScheduler.scheduleAtFixedRate(WebSocketConfigurationSupport.java:123)
at org.springframework.scheduling.config.ScheduledTaskRegistrar.scheduleFixedRateTask(ScheduledTaskRegistrar.java:462)
at org.springframework.scheduling.config.ScheduledTaskRegistrar.scheduleFixedRateTask(ScheduledTaskRegistrar.java:436)
at org.springframework.scheduling.config.ScheduledTaskRegistrar.scheduleTasks(ScheduledTaskRegistrar.java:357)
at org.springframework.scheduling.config.ScheduledTaskRegistrar.afterPropertiesSet(ScheduledTaskRegistrar.java:332)
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.finishRegistration(ScheduledAnnotationBeanPostProcessor.java:280)
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:211)
at org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor.onApplicationEvent(ScheduledAnnotationBeanPostProcessor.java:102)
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:399)
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:353)
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:887)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.finishRefresh(ServletWebServerApplicationContext.java:161)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:552)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:140)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:388)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:327)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1246)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1234)
at com.yeadev.JavaSpringBootJARAngularSeed.JavaSpringBootJarAngularSeedApplication.main(JavaSpringBootJarAngularSeedApplication.java:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
source code for WebSocketConfiguration
#Slf4j
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
// added end point,
// eg. ws://localhost:8080/ws
// added WebSocketHandler to /ws
registry.addHandler(new WebSocketHandler(),"/ws");
log.info("added handler for WebSocket.");
}
}
source code for ScheduledTasks
#Slf4j
#Component
public class ScheduledTasks {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
// #Scheduled() annotation can not use with WebSocketConfigurer
#Scheduled(fixedRate=1000)
public void reportCurrentTime() {
log.info("The time is now {}", dateFormat.format(new Date()));
}
}
i use Spring Boot 2.0.0.RELEASE

I ran into the same issue today. It looks as if like Spring web socket creates its own taskScheduler bean which doesn't implement any of the normal operations - it just throws IllegalStateException. This bean is then used for all #Scheduled methods. I was able to resolve this by explicitly creating a task scheduler bean in my ApplicationConfig:
#Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(10);
taskScheduler.initialize();
return taskScheduler;
}

Related

Mocking DAO object with MockMvc in Spring Boot

I am new to Integration testing. I have Spring Integration application for which I am writing test cases. here is how I am writing test case:
Activator:
#Service
public class ProdAppActivator {
#Autowired
private ApplicantDAO applicantDAO;
#Transactional
public ApplicantDTO prodApp(ApplicantDTO applicant)
throws TechnicalException, BusinessException {
applicantDAO.updateApp(applicant);
return application;
}
}
Test Class:
public class AcctImplTest extends AbstractTest {
#MockBean
private ApplicantDAO applicantDAO;
#Override
#Before
public void setUp() {
super.setUp();
}
#Test
public void testProdApp() throws Exception {
ProdAppRequest appRequest = getProdAppRequest();
mvc.perform(post("/baseurl/applicant").headers(getHeaders()).accept(MediaType.APPLICATION_JSON)
.content(mapToJson(appRequest)).contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
}
}
AbstractTest:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:group/deposit/svc/product-application-context-test.xml" })
#WebMvcTest
//#IfProfileValue(name ="profiles.active", value ="Integration")
public abstract class AbstractTest {
protected MockMvc mvc;
#Autowired
WebApplicationContext webApplicationContext;
protected void setUp() {
setCMD();
mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
I have 2 issues:
This activator has a method with #Transactional annotation. I am not sure why but because of this annotation my test getting failed and giving error as:
java.lang.ClassLoader.loadClass(ClassLoader.java:424)
sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
java.lang.ClassLoader.loadClass(ClassLoader.java:357)
org.springframework.orm.hibernate4.HibernateTransactionManager.isSameConnectionForEntireSession(HibernateTransactionManager.java:711)
org.springframework.orm.hibernate4.HibernateTransactionManager.doBegin(HibernateTransactionManager.java:445)
org.springframework.transaction.support.AbstractPlatformTransactionManager.getTransaction(AbstractPlatformTransactionManager.java:378)
org.springframework.transaction.interceptor.TransactionAspectSupport.createTransactionIfNecessary(TransactionAspectSupport.java:474)
org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:289)
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98)
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:185)
org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
com.hsbc.group.depositproduct.us.svc.activators.RecordProdAppActivator$$EnhancerBySpringCGLIB$$d1f3f882.recordProdApp(<generated>)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:498)
When I remove this annotation everything works fine. But I don't want to remove this annotation so can some please suggest how to write test here.
if I remove #Transactional annotation; I have used #MockBean to mock DAO object(Interface) and its mocking given object but when I try to return expected value for any DAO call its returning default value. Can some one please suggest how to mock DAO while using #MockBean. I have tried #SpyBean, and other possible ways but didn't get success.
Thanks in advance.

How to completely disable Spring Boot Autoconfiguration?

I'm working on an app and I only want to use Spring's DI features. My problem is that I can't manage to disable Spring Boot's autoconfiguration features. I keep getting this exception:
2020-06-26 14:00:03.240 [main] TRACE o.s.b.diagnostics.FailureAnalyzers - Failed to load org.springframework.boot.autoconfigure.jdbc.HikariDriverConfigurationFailureAnalyzer
java.lang.NoClassDefFoundError: org/springframework/jdbc/CannotGetJdbcConnectionException
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructor0(Class.java:3075)
at java.lang.Class.getDeclaredConstructor(Class.java:2178)
at org.springframework.boot.diagnostics.FailureAnalyzers.loadFailureAnalyzers(FailureAnalyzers.java:75)
at org.springframework.boot.diagnostics.FailureAnalyzers.<init>(FailureAnalyzers.java:66)
at org.springframework.boot.diagnostics.FailureAnalyzers.<init>(FailureAnalyzers.java:60)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:204)
at org.springframework.boot.SpringApplication.createSpringFactoriesInstances(SpringApplication.java:441)
at org.springframework.boot.SpringApplication.getSpringFactoriesInstances(SpringApplication.java:427)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1237)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
at MyApplication.main(MyApplication.java:19)
I tried not using #SpringBootApplication only #ComponentScan, but it didn't work. I also tried excluding the relevant autoconfiguration classes:
#SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
JdbcTemplateAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
XADataSourceAutoConfiguration.class})
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication .class, args);
}
}
but this is not working either. How can I get rid of autoconfiguration completely? I didn't find a #DisableAutoConfiguration annotation, yet there is a #EnableAutoConfiguration.
Edit:
My beans are configured in a separate file in the same package as my application class:
#Configuration
public class BeanConfig {
#Bean
public Database database() {
return DatabaseConfig.configureDatabase();
}
#Bean
public UserRepository userRepository() {
return new InMemoryUserRepository(
Collections.singletonList(new UserEntity(
1,
"user",
Arrays.asList(Permission.ADOPT.name(), Permission.EDIT_PROFILE.name()))));
}
#DependsOn("database")
#Bean
public DogRepository dogRepository() {
return new H2DogRepository();
}
#Bean
public AdoptDog adoptDog() {
return new AdoptDog(dogRepository());
}
#Bean
public FindDogs findDogs() {
return new FindDogs(dogRepository());
}
#Bean
public CreateDog createDog() {
return new CreateDog(dogRepository());
}
#Bean
public DeleteDogs deleteDogs() {
return new DeleteDogs(dogRepository());
}
#Bean
public FindUser findUser() {
return new FindUser(userRepository());
}
#PostConstruct
public void initialize() {
ApplicationEngine engine = ServerConfig.configureServer(
userRepository(), adoptDog(), findDogs(), createDog(), findUser(), deleteDogs());
DogUtils.loadDogs().forEach(dogRepository()::create);
CheckerUtils.runChecks(engine, userRepository());
}
}
I have a different server technology, and I'm using this project to demonstrate Kotlin-Java interoperability (all these files are Kotlin files which are referenced here).
The problem was that Spring was looking for classes which I didn't have (I'm not using any of them) but was necessary for it to work.
Once I added "org.springframework.boot:spring-boot-starter-data-jdbc" and "javax.validation:validation-api:2.0.1.Final" as dependencies it started to work.
Add only spring-boot to dependencies (don't use *-starter-*)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
</dependency>
, and use #ComponentScan instead of #SpringBootApplication.
Actually this may be down to spring.factories in some of your jars and authors violating it. (i.e not listing them under the key of EnableAutoConfiguration as per https://docs.spring.io/autorepo/docs/spring-boot/2.0.0.M3/reference/html/boot-features-developing-auto-configuration.html
In this example, an Application Listener will be registered regardless of auto config enabled or not. May be some of the jars in your class path have beans defined in spring factories
https://www.logicbig.com/tutorials/spring-framework/spring-boot/application-listener-via-spring-factories.html

Spring Batch Multiple DataSource Session/Entitymanager Closed

I am trying to Pull Records from SQLServer Database to Persist into Mysql Using Spring Boot and Sprin Batch(JpaPagingItemReader and JpaItemWriter).
I have configured Multiple Datasources.
How ever i am facing with below error.
org.springframework.batch.item.ItemStreamException: Error while closing item reader
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close(AbstractItemCountingItemStreamItemReader.java:138)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.DisposableBeanAdapter.invokeCustomDestroyMethod(DisposableBeanAdapter.java:337)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:271)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:571)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:543)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:957)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:504)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:964)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1041)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1017)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:967)
at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:377)
at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:597)
at net.com.org.batch.MyApplication.main(MyApplication.java:15)
Caused by: java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.checkOpen(AbstractSharedSessionContract.java:344)
at org.hibernate.engine.spi.SharedSessionContractImplementor.checkOpen(SharedSessionContractImplementor.java:137)
at org.hibernate.internal.AbstractSharedSessionContract.checkOpenOrWaitingForAutoClose(AbstractSharedSessionContract.java:350)
at org.hibernate.internal.SessionImpl.close(SessionImpl.java:413)
at org.springframework.batch.item.database.JpaPagingItemReader.doClose(JpaPagingItemReader.java:232)
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.close(AbstractItemCountingItemStreamItemReader.java:135)
... 17 common frames omitted
20:10:55.875 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Retrieved dependent beans for bean 'jpaMappingContext': [mySqljobRepository, sqlServerLogsRepository]
Below is my Batch,Step Configuration
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
#Qualifier("mysqlEntityManager")
private LocalContainerEntityManagerFactoryBean mysqlLocalContainerEntityManagerFactoryBean;
#Autowired
#Qualifier("secondarySqlEntityManager")
private LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean;
#Autowired
#Qualifier("mysqlTransactionManager")
private PlatformTransactionManager mySqlplatformTransactionManager;
#Autowired
#Qualifier("secondaryTransactionManager")
private PlatformTransactionManager secondaryTransactionManager;
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Bean
public JpaPagingItemReader itemReader(PlatformTransactionManager secondaryTransactionManager) {
JpaPagingItemReader<SqlServerJobLogs> serverJobLogsJpaPagingItemReader = new JpaPagingItemReader<>();
serverJobLogsJpaPagingItemReader.setMaxItemCount(1000);
serverJobLogsJpaPagingItemReader.setPageSize(100);
serverJobLogsJpaPagingItemReader.setEntityManagerFactory(localContainerEntityManagerFactoryBean.getNativeEntityManagerFactory());
serverJobLogsJpaPagingItemReader.setQueryString("select p from SqlServerJobLogs p");
return serverJobLogsJpaPagingItemReader;
}
#Bean
public ItemProcessor itemProcessor() {
return new DataItemProcessor();
}
#Bean
public ItemWriter itemWriter(PlatformTransactionManager mySqlplatformTransactionManager) {
DataWriter dataWriter = new DataWriter();
return dataWriter;
}
#Bean
public Step step() {
return stepBuilderFactory.get("myJob").chunk(100).reader(itemReader(secondaryTransactionManager)).processor(itemProcessor()).writer(itemWriter(mySqlplatformTransactionManager)).build();
}
#Bean(name = "myJob")
public Job myJob() throws Exception {
return jobBuilderFactory.get("myJob").start(step()).build();
}
#Bean
public ResourcelessTransactionManager resourcelessTransactionManager(){
return new ResourcelessTransactionManager();
}
#Bean
public JobRepository jobRepository() throws Exception{
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(resourcelessTransactionManager());
return mapJobRepositoryFactoryBean.getObject();
}
#Bean
public SimpleJobLauncher jobLauncher() throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository());
return simpleJobLauncher;
}
I have Tried to Configure BatchConfigurer.But No luck.
Please let me know if i need to configure anything else apart from the above mentioned details
Thanks in Advance
I would like to answer the question.
A big thanks to #MahmoudBenHassine
Providing a custom transaction manager by overriding
DefaultBatchConfigurer#getTransactionManager works only with Spring
Batch v4.1+ as said in comments. We need to use Spring Boot v2.1 to
have Spring Batch 4.1

Spring boot application does not find placeholder 'spring.embedded.kafka.brokers' for a spock-spring test

I am trying to do an integration test with Spring Boot, Spock-Spring and Embedded Kafka. I followed this guide, where I found "As the embedded broker is started on a random port, we can’t use the fix value in the src/main/resources/application.yml properties file. Luckily the #ClassRule sets a spring.embedded.kafka.brokers system property to the address of the embedded broker(s)." Hence I have
#ContextConfiguration
#SpringBootTest(classes = [Application], webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#DirtiesContext
#Stepwise
#ActiveProfiles("test")
class AnIntegrationTest extends Specification {
#Autowired
private KafkaListenerEndpointRegistry kafkaListenerEndpointRegistry
#ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, "topic")
private KafkaTemplate<String, String> template
def setup() {
Map<String, Object> senderProperties = KafkaTestUtils.senderProps(embeddedKafka.getBrokersAsString())
ProducerFactory<String, String> producerFactory =
new DefaultKafkaProducerFactory<String, String>(senderProperties)
template = new KafkaTemplate<>(producerFactory)
template.setDefaultTopic("topic")
for (MessageListenerContainer messageListenerContainer : kafkaListenerEndpointRegistry
.getListenerContainers()) {
ContainerTestUtils.waitForAssignment(messageListenerContainer, embeddedKafka.getPartitionsPerTopic())
}
}
def "test"() {
given:
template.sendDefault("Hello")
}
}
In application-test.yml I have
kafka:
bootstrapservers: ${spring.embedded.kafka.brokers}
In the application I start a Kafka consumer with spring-kafka.
Stack trace is
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:124)
at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:83)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:117)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:83)
at org.springframework.boot.test.autoconfigure.SpringBootDependencyInjectionTestExecutionListener.prepareTestInstance(SpringBootDependencyInjectionTestExecutionListener.java:44)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:230)
at org.spockframework.spring.SpringTestContextManager.prepareTestInstance(SpringTestContextManager.java:50)
at org.spockframework.spring.SpringInterceptor.interceptSetupMethod(SpringInterceptor.java:42)
at org.spockframework.runtime.extension.AbstractMethodInterceptor.intercept(AbstractMethodInterceptor.java:28)
at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:87)
at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:88)
at org.spockframework.runtime.extension.builtin.AbstractRuleInterceptor$1.evaluate(AbstractRuleInterceptor.java:37)
at org.togglz.junit.TogglzRule$1.evaluate(TogglzRule.java:127)
at org.spockframework.runtime.extension.builtin.TestRuleInterceptor.intercept(TestRuleInterceptor.java:38)
at org.spockframework.runtime.extension.MethodInvocation.proceed(MethodInvocation.java:87)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'kafkaListenerContainerFactoryConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.embedded.kafka.brokers' in value "${spring.embedded.kafka.brokers}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:372)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:122)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:693)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:360)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:303)
at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:120)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:98)
at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:116)
... 19 more
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'spring.embedded.kafka.brokers' in value "${spring.embedded.kafka.brokers}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:174)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)
at org.springframework.core.env.AbstractPropertyResolver.resolveNestedPlaceholders(AbstractPropertyResolver.java:227)
at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:84)
at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:61)
at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:527)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$1.getProperty(PropertySourcesPlaceholderConfigurer.java:132)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$1.getProperty(PropertySourcesPlaceholderConfigurer.java:129)
at org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:81)
at org.springframework.core.env.PropertySourcesPropertyResolver.getPropertyAsRawString(PropertySourcesPropertyResolver.java:71)
at org.springframework.core.env.AbstractPropertyResolver$1.resolvePlaceholder(AbstractPropertyResolver.java:239)
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:147)
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126)
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:236)
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210)
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer$2.resolveStringValue(PropertySourcesPlaceholderConfigurer.java:172)
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:831)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1086)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
... 36 more
Does anyone have a clue?
Ensure that in each of your integration test you setup both #SpringBootTest and #EmbeddedKafka.
This is common mistake when you run multiple integration tests at once with #SpringBootTest annotation. Since you have registered DefaultKafkaConsumerFactory and DefaultKafkaProducerFactory in your application configurator bean and probably you also use #Value("${spring.kafka.bootstrap-servers}") somewhere there, you are obligated to setup #EmbeddedKafka(partitions = 1, topics = {"topic"}) everywhere you call spring-boot application to run on test server container. #EmbeddedKafka is responsible to call EmbeddedKafkaContextCustomizer to register all environment variables (among others spring.embedded.kafka.brokers) needed by kafka engine.
Without #EmbeddedKafka in your Integration Test spring runs your application on server but there is no mechanism to set up environments used by kafka engine.
I invoked embeddedKafka.before() in setup(). Then the spring.embedded.kafka.brokers got set and available.
I am not sure, but the problem seems like Spock Spring specific.
I am not familiar with Spock but a simple Java JUnit test works fine...
#SpringBootApplication
public class So47172973Application {
public static void main(String[] args) {
SpringApplication.run(So47172973Application.class, args);
}
#KafkaListener(topics = "foo")
public void in(String in) {
System.out.println(in);
}
}
and
spring:
kafka:
bootstrap-servers:
- ${spring.embedded.kafka.brokers}
consumer:
group-id: embedded1
auto-offset-reset: earliest
and
#RunWith(SpringRunner.class)
#SpringBootTest
public class So47172973ApplicationTests {
#ClassRule
public static KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, "foo");
#Autowired
private KafkaTemplate<String, String> template;
#Test
public void test() throws InterruptedException {
template.send("foo", "bar");
Thread.sleep(10_000);
}
}
A couple of things to try:
Use the annotation instead...
#RunWith(SpringRunner.class)
#SpringBootTest
#EmbeddedKafka(controlledShutdown = true, topics = "foo")
public class So47172973ApplicationTests {
#Autowired
private KafkaTemplate<String, String> template;
#Test
public void test() throws InterruptedException {
template.send("foo", "bar");
Thread.sleep(10_000);
}
}
declare the broker as a #Bean...
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {So47172973ApplicationTests.Config.class, So47172973Application.class})
public class So47172973ApplicationTests {
#Autowired
private KafkaTemplate<String, String> template;
#Test
public void test() throws InterruptedException {
template.send("foo", "bar");
Thread.sleep(10_000);
}
#Configuration
public static class Config {
#Bean
public KafkaEmbedded embeddedKafka() {
return new KafkaEmbedded(1, true, "foo");
}
}
}
Got the similar issue and #taro's answer didn't resolve my issue.
I fixed this issue by removing static from EmbeddedKafka object and replacing #ClassRule with #Rule annotation.
#Rule
public KafkaEmbedded embeddedKafka = new KafkaEmbedded(1, true, "topic")

Spring #EnableCaching with #Inject/#Autowired issue

I found an issue when using #EnableCaching annotation together with #Inject/#Autowired in #Configuration class:
Simple example to reproduce:
Configuration class:
#Configuration
#EnableCaching
public class CacheConfig {
#Inject
private DataSource dataSource;
#Bean
public CacheManager cacheManager(){
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new ConcurrentMapCache("books")));
return cacheManager;
}
#Configuration
static class DevProfileConfig {
#Bean(destroyMethod = "shutdown")
public DataSource dataSource() {
EmbeddedDatabaseFactory factory = new EmbeddedDatabaseFactory();
factory.setDatabaseType(EmbeddedDatabaseType.HSQL);
return factory.getDatabase();
}
}
}
Application context launcher:
public class CacheConfigLauncher {
public static void main(String args[]){
ApplicationContext springAppContext = new AnnotationConfigApplicationContext(CacheConfig.class);
}
}
Error:
Caused by:
org.springframework.beans.factory.BeanDefinitionStoreException:
Factory method [public org.springframework.cache.CacheManager
spring.samples.config.CacheConfig.cacheManager()] threw exception;
nested exception is java.lang.IllegalArgumentException: Object of
class [null] must be an instance of interface
org.springframework.beans.factory.config.ConfigurableBeanFactory at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188)
at
org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:573)
... 76 more
Caused by: java.lang.IllegalArgumentException: Object of class [null]
must be an instance of interface
org.springframework.beans.factory.config.ConfigurableBeanFactory at
org.springframework.util.Assert.isInstanceOf(Assert.java:339) at
org.springframework.util.Assert.isInstanceOf(Assert.java:319) at
org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.getBeanFactory(ConfigurationClassEnhancer.java:414)
at
org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:289)
at
spring.samples.config.CacheConfig$$EnhancerByCGLIB$$f6ceccea.cacheManager()
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:491) at
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166)
... 77 more
However if you comment out either #Inject'ed field or #EnableCaching annotation configuration will be bootstraped without errors!!!
It seams like a bug for me. Have someone faced the same issue or probably I'm missing smth?
Thank you,
Oleg
Issue has been fixed in Spring v4.0.0.M2!

Resources