Spring Scheduled task: Scope 'request' is not active for the current thread - spring

I am writing a project with Spring Boot 1.5.8.
I have some Entity classes which are generated and contain bean (for Example FooBean) which only exists in request scope. What is important: i am not able to change that part of code. So assume that i have an Entty:
#Enitty
public class FooEntity{
#Transient protected FooBean fooBean;
}
and FooBean implementation:
#Component
#Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public class FooBean {
...
}
I also have some part of code where i have method which should be runned by Spring CRON:
#Scheduled(cron = "0 0/2 * * * ?")
#Transactional(value = Transactional.TxType.REQUIRES_NEW)
void scheduledTask() {
...
}
What's important: in that scheduledTask i am saving some instances of FooEntity to DB.
And of course: When i try to invoke repository.saveAll() Spring is throwing an exception:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.fooBean ': Scope 'request' is not active for the current thread;
Is there any possibility to resolve that problem? How can I override this scoped bean so it will be available in not-request scope?

I think I'm writing a little bit later :) but you can create your own instance of this bean.
In spring boot you can simply create your own singleton instance of the bean like this:
#Configuration
#EnableScheduling
public class ApiConfig {
#Bean
#Primary
public FooBean fooBean(){
return new FooBean();
}
}
In case your bean has some dependencies in constructor (constructor autowired) which has to be autowired you can simply put those beans in method params and spring will provide it for you like this:
#Bean
#Primary
public FooBean fooBean(BeanToAutowire myBean){
return new FooBean(myBean);
}
In case your bean has no constructor autowired dependencies but annotation autowired (using #Autowired) you can simple do it like this:
#Bean
#Primary
public FooBean fooBean(AutowireCapableBeanFactory beanFactory){
FooBean bean = new FooBean(myBean);
beanFactory.autowireBean(bean); // here spring will autowire all dependencies for you
return bean;
}
It is not the most elegant way to do it but it works. Side effect is that there will be two instances of FooBean in app context but spring will use your instance because you set this instance as primary using #Primary annotation. Only beans which use Autowired annotation together with qualifier annotation can choose which instance of FooBean will be autowired.

Related

Spring Profile for Autowired Bean

For my Spring Boot App, I am using Profile. Following is my Bean Class:
#Profile("container")
#Bean
public class ConfigService {
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
Now, I want to use this bean in another class and do so via with auto wired:
#Autowired
private ConfigSevice config;
This work as long as the profile "container" active is, but the application throws an unsatisfied dependeny error referring the autowired bean when the profile is not active in the class where the bean is used. How can I solve this problem?
Use
#Autowired(required = false)
But be careful. If you call a method on this dependency when profile is not active, you will get a nullpointer exception.

NoSuchBeanDefinitionException - SpringBoot autowired constructor contains param that has an autowired declaration that is not being generated

I have the following code:
This is my first class that will to call the
#Component
class DefaultBridge #Autowired constructor(
private val clientConfig: Config,
private val client: world.example.Client
) : Bridge {
override fun doEpicStuff(): String {
val request = createRequest(...)
val response = client.makeCall(request)
return response.responseBody
}
}
The Client being used (world.example.Client) then has the following piece of code:
public class Client {
#Autowired
private RestTemplate restTemplate;
public Response makeCall(Request request) {
restTemplate.exchange(....)
}
}
When running the code. I get the following Error:
NoSuchBeanDefinitionException: No qualifying bean of type
'org.springframework.web.client.RestTemplate' available: expected at
least 1 bean which qualifies as autowire candidate. Dependency
annotations:
{#org.springframework.beans.factory.annotation.Autowired(required=true)}
Where should I declare the bean when the constructor is autowired?
why won't spring automatically create the bean?
I need help understanding the problem so please don't just post the solution.
With Spring dependency injection you can inject a instance of a bean.
In Spring it's called Inversion of Control (IoC) principle. IoC is also known as dependency injection (DI).
You can define depencenies for your bean with member variable or constuctor variables. There are differnt possibilities, for example #Autowire as annotation for member variables like your usage.
The container then injects those dependencies when it creates your bean.
Attention, however, it is necessary that the spring container knows how the dependency to be injected. There are many ways to teach the container this. The simplest variant is to provide a #Bean producer method in a #Configuration class. Spring container "scans" all #Configurations at the start of the container and "registers" the #Bean producer.
Nobody has done a producer for RestTemplate. Not Spring self and also no other lib. With many other beans you use, this has already been done, not with RestTemplate. You have to provide a #Bean producer for RestTemplate.
Do this in a new #Configuration or in one of your existing #Configuration.
A #Configuration indicates that a class declares one or more #Bean methods and may be processed by the Spring container to generate bean definitions and service requests for those beans at runtime, for example:
#Configuration
public class RestTemplateConfig {
#Bean
public RestTemplate restTemplate() {
// New instance or more complex config
return new RestTemplate();
}
}
Define RestTemplate as a bean in your configuration class.

POJO Injection in Spring similar to CDI

I have some java objects coming from external library which I need to inject in my spring project. Problem is the classes from library is not aware of any spring api's
If I inject the beans from library to Service using #Autowired I am getting org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type
Following is my service class
#Path("/test")
public class TestService {
#Autowired
SomeOtherClass service;
#GET
public Response get(){
return Response.ok(service.someMethod()).build();
}
}
and following is my class from library which is not aware of spring
public class SomeOtherClass {
public String someMethod(){
return "Data from library";
}
}
When I invoke my service I get exception as
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.SomeOtherClass' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
Is there are way in spring to inject a plain Java Object similar to that of injection in **CDI**?
There is one option to define applicationcontext.xml and define SomeOtherClass in xml and use getBean, but I don't want to do that. Is there any other option?
Note:
Following options cannot be considered because I have100's of classes coming from library
Cannot use applicationcontext.xml
Cannot #Configuration #Bean to produce beans.
You could use the #Configuration and #Bean annotations as follows -
Create a new class:
#Configuration
public class AppConfig {
#Bean
SomeOtherClass someOtherClassBean(){ return new SomeOtherClass();}
}
Now the auto wiring shall work.
What it does, is actually creating a bean and letting Spring know about it.
Maybe try adding the beans programatically to the IoC container:
Add Bean Programmatically to Spring Web App Context
You need to find all the classes you want to instantiate and use one of the methods in the linked question.
You can use reflection to add Bean definitions programatically.
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
Reflections ref = new Reflections(new ConfigurationBuilder()
.setScanners(new SubTypesScanner(false /* don't exclude Object.class */), new ResourcesScanner())
.setUrls(ClasspathHelper.forPackage(PACKAGE_NAME))
.filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix(PACKAGE_NAME))));
ref.getSubTypesOf(Object.class).stream()
.forEach(clazz -> {
logger.info("Defining pojo bean: {} -> {}", Introspector.decapitalize(clazz.getSimpleName()), clazz.getCanonicalName());
registry.registerBeanDefinition(Introspector.decapitalize(clazz.getSimpleName()),
BeanDefinitionBuilder.genericBeanDefinition(clazz).getBeanDefinition());
});
}
Subsequently, these beans can be #Autowired elsewhere. See Gist: https://gist.github.com/ftahmed/a7dcdbadb8bb7dba31ade463746afd04

Spring #Bean method executing after #Autowired

I use Spring Boot MVC application.
I have a #Configuration class that initializes a bean into ApplicationContext using #Bean.
I have a #Controller class into which I am trying to autowire the bean using #Autowired annotation.
Result: #Autowired field is null.
DEBUG: I tried to debug to see the order of execution. I was expecting to see that class annotated with #Configuration will run first to initialize bean into application context. However, controller class got instantiated first. Then #Bean method of configuration class got called next. Due to this bean is instantiated after controller and that is why Controller is not getting bean autowired.
Question: How to have #Configuration #Bean method execute prior to the controller class instantiation?
code for configuration class:
#Configuration
public class RootConfiguration2 {
#Autowired
private IService<ActBinding> bindingService;
#Bean
public Map<String, String> getBingindNameToRoutingKeyMap() throws Exception {
ListOperation<ActBinding> operation = ListOperation.from("key", "name", "exchangeId");
operation.sort("key", SortOrder.Ascending);
Iterable<ActBinding> result = bindingService.list(operation).getResult();
Map<String, String> bindingNameToRoutingKey = new HashMap<>();
result.forEach(x -> bindingNameToRoutingKey.put(x.getName(), x.getKey()));
return Collections.unmodifiableMap(bindingNameToRoutingKey);
}
}
I found two workarounds. Both solutions worked:
1. Use #Resource instead of #Autowired to inject the bean into controller.
2. Use #PostConstruct on the method annotated with #Bean in Configuration class.
Note: You dont have to do both of the changes. Any one of them should work.

Reasons for autowired beans in spring being null

I've come across a problem that at run time autowired beans in a certain class are all null. I would like an answer that will cover all possibilities on why a spring autowired bean is not initialised.
Only java config is used, no xml files at all
New keywords are only used at bean definitions
All classes and fields are annotated appropriately
Eg:
#ComponentScan(...
#Configuration
public...
#Bean
public ... myBean(){
return new ...;
}
#Service
public ...
#Autowired
private ... myBean ;
And I guess this is when I am trying to use service;
#Configuration
public ...
// Constructor
service = new Service();
// Field
private Service service;
The most likely reason is object instance is not a spring bean (the one which you want to inject something) in other words: Spring does not know the instance, and therefore does not care about it
BTW: if Spring would know/take care of that instance and would not find a matching bean, then the default result for #Autowired is an exception

Resources