I'm getting:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.mz.server.rest.braintree.webhooks.SubscriptionWebhook]: No default constructor found; nested exception is java.lang.NoSuchMethodException: com.mz.server.rest.braintree.webhooks.SubscriptionWebhook.<init>()
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:85)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1098)
... 22 more
Even though I have defined this constructor in my applicatioContext-restapi.xml file:
<bean id="subscriptionWebhook" class="com.mz.server.rest.braintree.webhooks.SubscriptionWebhook">
<constructor-arg ref="dslContext" />
</bean>
Any idea why?
#RestController
public class SubscriptionWebhook {
private final static Logger LOGGER = Logger.getLogger(SubscriptionWebhook.class.getName());
private AdminService adminService;
public SubscriptionWebhook(DSLContext ctx) {
this.adminService = new AdminService(ctx);
}
}
Since Spring 3(ish) you can configure your container by applying #Component annotations to classes. #Controller annotation is defined as follows:
#Target(value=TYPE)
#Retention(value=RUNTIME)
#Documented
#Component
public #interface Controller
Which means classes annotated by it are going to get picked up, too. And RestController is just Controller and ResponseBody put together.
Anyway as you admitted in the comments you have enabled component scanning, and the configuration in xml is not going to get picked up in this case.
What you could do is convert the xml configuration to annotation-based injection, like that:
#RestController
public class SubscriptionWebhook {
private final static Logger LOGGER = Logger.getLogger(SubscriptionWebhook.class.getName());
private AdminService adminService;
public SubscriptionWebhook(#Qualifier("dslContext") DSLContext ctx) {
this.adminService = new AdminService(ctx);
}
}
Qualifier annotation is going to look in the container for a bean with name/id dslContext and inject it in the constructor. Alternatively you can use the javax.inject Named annotation, or if this is the only bean with that type, Spring's #Autowired or JSR-330's #Inject.
Annotation #RestController is autodetected by spring. Spring will create a bean for you so you shouldn't add bean definition in the xml, because it would create a second bean. If you want to inject another bean into the controller just use #Autowired. So the solution in your case is:
Remove "subscriptionWebhook" bean definition from the xml
Add #Autowired on SubscriptionWebhook constructor
Related
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.
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
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.
I have a bean that looks like this:
#Component
#Scope("session")
public class AlarmChartSettingsBean implements Serializable {
...
Inside this bean i inject another bean like this:
#Inject
private SessionInfoBean sessionInfoBean;
Then i call the injected bean inside the constructor of the first bean like this:
public AlarmChartSettingsBean() {
String atcaIp = sessionInfoBean.getNwConfigBean().getAtcaIP();
}
The problem is that the injected bean is null. So the question is when is that bean injected? Can i use it inside the constructor or i should use it after the bean has been constructed?
The constructor of a Spring bean is called before Spring has any chance to autowire any fields. This explains why sessionInfoBean is null inside the constructor.
If you want to initialize a Spring bean, you can:
annotate a method with #PostConstruct:
#PostConstruct
public void init() {
String atcaIp = sessionInfoBean.getNwConfigBean().getAtcaIP();
}
implement InitializingBean and write the initialization code inside the afterPropertiesSet method:
public class AlarmChartSettingsBean implements Serializable, InitializingBean {
#Override
void afterPropertiesSet() {
String atcaIp = sessionInfoBean.getNwConfigBean().getAtcaIP();
}
}
The #Inject on a Field will autowire after the constructor has been called.
Note: In some Spring-Apps the #Inject may not work, use #Autowire instead.
I am trying to use Spring annotation to define controller, service and dao, but failed.
the error message is
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.abs.absbase.ABSService] is defined: Unsatisfied dependency of type [interface com.abs.absbase.ABSService]: expected at least 1 matching bean
but I do define the service.
Another question is, how to define a sessionfactory to overwrite the HibernateDaoSupport in the ABSDaoImpl ?
Thanks
Source code is
#Controller
#RequestMapping("/abs.do")
public class ABSController {
#Autowired
#Qualifier("ABSService")
ABSService service;
...
}
#Service(value="ABSService")
public class ABSServiceImpl implements ABSService {
#Autowired
#Qualifier("ABSDao")
ABSDao dao;
}
#Repository(value="ABSDao")
public class ABSDaoImpl extends HibernateDaoSupport implements ABSDao {
...
}
According to me you just need to remove the #Qualifier annotation you have defined above the declaration of ABSService object in the controller. And also remove the (value="ABSService") from the #Service annotation on the service.
Hope this helps you.
Cheers.