Spring autowiring issue with CommandLineRunner - java

Out of curosity i have the following question,i have one spring boot application running using commnad line runner where kinesis consumers would be running :
#SpringBootApplication
public class FleetMessagingKCLApplication implements CommandLineRunner{
//Command line runner
#Override
public void run(String... args) throws Exception {
kinesisconsumers.startConsumers();
}
}
I have one service locator bean in the MAIN class(mentioned below) having interface Processor Factory for Factory Pattern implementation:
#Bean
public ServiceLocatorFactoryBean serviceLocatorForMessageTransformation() {
ServiceLocatorFactoryBean slfb = new ServiceLocatorFactoryBean();
slfb.setServiceLocatorInterface(ProcessorFactory.class);
return slfb;
}
But was not able to autowire the ProcessFactory in any of the classes,but after moving the service locator bean bean into another java class declared with Component, autowiring worked as expected.
Was thing someting related to using command line runner that i was not able to autowire?

Related

Request-scoped beans not working in Spring tests with Cucumber

I have an application based on Spring 4.3.28 (i.e. not Spring Boot!) and I want to migrate my integration tests to Cucumber.
I’ve followed this tutorial and adapted it to plain Spring.
The tests I’ve written so far are working fine (Spring context is initialized etc.), but as soon as there are request-scoped beans involved, they stop working:
Caused by: java.lang.IllegalStateException: No thread-bound request found: Are you
referring to request attributes outside of an actual web request, or processing a
request outside of the originally receiving thread? If you are actually operating
within a web request and still receive this message, your code is probably running
outside of DispatcherServlet/DispatcherPortlet: In this case, use
RequestContextListener or RequestContextFilter to expose the current request.
I’ve created a small sample project
that tries to reproduce the problem.
There is one context configuration class called AppConfig:
#Configuration
public class AppConfig {
#Bean
#Scope("request“) // when this line is removed, the test succeeds
public ExampleService exampleService() {
return new ExampleService();
}
#Bean("dependency")
#Scope("request") // when this line is removed, the test succeeds
public String dependencyBean() {
return "dependency bean";
}
}
The ExampleService is request-scoped, and gets one request-scoped bean injected by #Autowired:
public class ExampleService {
#Autowired
#Qualifier("dependency")
String dependencyBean;
public String process() { return "I have a "+dependencyBean; }
}
For the tests, I have one Spring-annotated superclass:
#ContextConfiguration(classes = AppConfig.class)
#CucumberContextConfiguration
#WebAppConfiguration
public class TestBase {
#Autowired
public ExampleService underTest;
}
There’s also a plain Spring test that runs just fine:
#RunWith(SpringRunner.class)
public class ExampleServicePlainSpringTest extends TestBase {
#Test
public void whenProcessingDataThenResultShouldBeReturned() {
assertThat(this.underTest.process()).isEqualTo("I have a dependency bean");
}
}
The Cucumber test is executed by this test class stub:
#RunWith(Cucumber.class)
public class ExampleServiceCucumberTest extends TestBase {}
The actual cucumber step definitions are here:
public class CucumberStepDefinitions extends TestBase {
private String result;
#When("I process data")
public void iProcessData() {
result = this.underTest.process();
}
#Then("the result should be returned")
public void checkResult() {
assertThat(result).isEqualTo("I have a dependency bean");
}
}
The .feature file for Cucumber is in the src/test/resources directory under the same package name as the step definitions class:
Feature: Example
Scenario: Example service bean returns dependency
When I process data
Then the result should be returned
Usually when I encountered the „no thread-bound request found“ error, it was because the #WebAppConfiguration annotation was missing, or when I tried to inject a request-scoped bean into a non-request scoped bean. But that’s not the case here.
What am I doing wrong?
I was able to figure out how to resolve it; the updated code is in the github repository linked in the question.
When using the SpringRunner, the request context is initialized in a ServletTestExecutionListener that is implicitly added to the list of TestExecutionListeners for the test.
The initialization happens in the beforeTestMethod() method of that listener.
However, as #M.P.Korsanje correctly remarked in the comments (thanks!), Cucumber doesn't have test methods, so beforeTestMethod() is never executed.
My solution was to add a custom subclass of ServletTestExecutionListener as a TestExecutionListener that delegates the beforeTestClass() call to the beforeTestMethod():
public class ClassLevelServletTestExecutionListener extends ServletTestExecutionListener {
#Override
public void beforeTestClass(TestContext testContext) throws Exception {
super.beforeTestMethod(testContext);
}
#Override
public void afterTestClass(TestContext testContext) throws Exception {
super.afterTestMethod(testContext);
}
}
And in ExampleServiceCucumberTest:
#ContextConfiguration(classes = {AppConfig.class})
#CucumberContextConfiguration
#WebAppConfiguration
#TestExecutionListeners(ClassLevelServletTestExecutionListener.class)
// extend the Spring class to get the default TestExecutionListeners
public class TestBase extends AbstractJUnit4SpringContextTests {
#Autowired
public ExampleService underTest;
}

Getting null for Autowired bean created using Java config

I am creating a REST service in Spring boot. I am creating a bean in config class and trying to use in service class by auto wiring, but I am always getting null, I have tried in constructor injection as well but not working. Below is the code,
Main app
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
REST controller
#RestController
#RequestMapping("/v1")
public class RestController {
#Autowired
private Service service;
Service
#Service
public class ServiceImpl implements Service {
//This is the bean
#Autowired
private Record record;
public ServiceImpl() { //-----------------> tried injecting in constructor as well
System.out.println(record); //-------------------> null
}
Config class
#Configuration
public class AppConfig {
#Bean
public Record record() {
return new Record("test");
}
}
I noted whenever I remove the record() from config class I get below error
required a bean of type 'com.ns.service.Record' that could not be found
And after adding the method the error is not reported but null is returned, which indirectly means record() is considered as returning the required bean.
I can't find what I am doing wrong please advise.
Project folder structure
I think you're doing everything right conceptually
Spring creates an object first and only after that injects the values (technically done in bean post processors):
So try this:
#Service
public class ServiceImpl implements Service {
//This is the bean
#Autowired
private Record record;
public ServiceImpl() {
// here the record is null - not injected yet
System.out.println(record);
}
#PostConstruct
public void checkThisOut() {
// here print the record
}
You say you've tried constructor injection as well - it should work because spring has to inject something into the constructor of a bean (ServiceImpl) or fail. Please show the code snippet
One this that might be wrong in some level (although it doesn't sound like this from your description) is that you have to put all the #Configuration/#Service annotated classes in the package that is the same or underneath the package where you've created the main class annotated with #SpringBootApplication annotation. It instructs spring boot where to look for the beans.
So make sure your classes obey this rule...

Cucumber + spring: How to trigger SmartLifecycle events through tests?

I have a spring boot application with cucumber. I would like to perform certain events within the test BEFORE the start-SmartLifecycle event of the beans is called.
Given Something that needs to happen before beans are started
And Beans start up now
Then Life is good
Is there any way to achieve this?
By default, it looks like Spring initializes and starts all the beans before any Cucumber statements are executed.
Example:
class Context {
#Bean
SomeBean someBean() { return new SomeBean(); }
}
class SomeBean implements SmartLifecycle {
#Override
void start() {
// some meaningful work that depends on setup that needs to be done beforehand
}
// rest of interface implementation
}
Cucumber definitions file:
#ContextConfiguration(classes = Context.class)
class CucumberFeatures {
#Autowired
private SomeBean someBean;
#Given("Something that needs to happen before beans are started")
public void something() {
// ...
}
#Given("Beans start up now")
public void beansStarted() {
// This should start beans in their defined order now
}
#Then("Life is good")
public void lifeIsGood() { ... }
}
You can't test a dependency injection container while using that same container to inject dependencies into your test. Injecting dependencies requires the application context to have been refreshed already.
So you have to create an instance of the ApplicationContext manually and manage it's life-cycle yourself.

Spring AOP adviced methods do not work. My configuration seems ok

I'm trying to create a demo AOP application but it just does not work right.
I read through all tutorials and got it working with #RestController but as I tried it with a plain java spring driven application I just can't get it to work. Please review my files and tell me where my mistake lies in.
Application Class
#SpringBootApplication
#ComponentScan("com.xetra.experimental")
#EnableAspectJAutoProxy
public class AoptryoutnowebApplication {
public static void main(String[] args) {
SpringApplication.run(AoptryoutnowebApplication.class, args);
DefaultClassToAspectImpl defaultClassToAspectImpl = new DefaultClassToAspectImpl();
defaultClassToAspectImpl.doStuff();
}
}
ClassToAspect Interface
public interface ClassToAspect {
void doStuff();
}
ClassToAspect Implementation
#Component
public class DefaultClassToAspectImpl implements ClassToAspect {
#FooAnnotation
public void doStuff(){
System.out.println("DoStuff!");
}
}
Annotation for Pointcut
public #interface FooAnnotation {
}
Aspect Class
#Aspect
public class FooAspect {
#Pointcut("#annotation(FooAnnotation)")
public void methods(){
}
#Before("methods()")
public void doAspect(){
System.out.println("FooAspect before");
}
}
Try this:
replace #EnableAspectJAutoProxy with #EnableAspectJAutoProxy(proxyTargetClass = false)
change pointcut to
#Pointcut("execution (* your.package..*.*(..)) && #annotation(fooAnnotation))")
The problem is you are using a non Spring managed instance by doing new DefaultClassToAspectImpl(). Spring AOP only works for Spring managed beans, because by default Spring AOP is proxy based.
So instead of doing new DefaultClassToAspectImpl() you should be obtaining the instance from the ApplicationContext. When using Spring Boot the SpringApplication.run call returns an ApplicationContext. Here you can use one of the getBean methods to obtain the instance you want.
ApplicationContext ctx = SpringApplication.run(AoptryoutnowebApplication.class, args);
ClassToAspect bean = getBean(ClassToAspect.class);
bean.doStuff();
This way you get the Spring managed

How can I declare a startup-hook in a Java Web App

I want to do some initializing (timers and logging) when the web app is started. I cannot use a ContextListener since I dont get any of my Spring-Components within it. I need a simple hook like "afterWebAppHasLoadedAndEverythingyIsSetUp()".
Does it exist?
The ApplicationContext publishes certain types of events when loading the beans.
Event handling in the ApplicationContext is provided through the ApplicationEvent class and ApplicationListener interface. So if a bean implements the ApplicationListener, then every time an ApplicationEvent gets published to the ApplicationContext, that bean is notified.
Following events are provided by spring
ContextRefreshedEvent
ContextStartedEvent
ContextStoppedEvent
ContextClosedEvent
Firstly create a implementation of ApplicationListener as follows
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
public class CStartEventHandler
implements ApplicationListener<ContextStartedEvent>{
public void onApplicationEvent(ContextStartedEvent event) {
System.out.println("ContextStartedEvent Received");
}
}
Then you just have to Register the class as a bean with the Spring.
If you are using Spring Boot (which i recommend), you can use the following CommandLineRunner bean to run your initialization stuff after the application started up. You will be able to get all the spring beans ready, below is the code snippet.
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class MyApplication extends SpringBootServletInitializer {
// here you can take any number of object which is anutowired automatically
#Bean
public CommandLineRunner init(MyService service, MyRepository repository) {
// do your stuff with the beans
return null;
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyApplication.class);
}
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

Categories

Resources