I have a method on my service, where I included a packaged (that is in a jar) from other libraries (that I cannot modify).
So, the included packages are in other contexts (I can reach them because they were included on my pom).
At the end, the problem is this.
On the class myService I have
private SomeService someService;
private boolean doSommething() {
try {
success = someService.somemethod();
} catch (InterruptedException exc) {
...
}
}
return success;
}
#Required
public void setMyService(SomeService someService) {
this.someService = someService;
}
From my app, I always get someService as null. Is there anyway to configure this to make it work? Like a bean configuration or something?
In your bean definitions, add this:
<bean id="someService" class="SomeService"/>
<bean id="myService" class="MyService">
<property name="someService" ref="someService"/>
</bean>
Make sure the method name in MyService is:
setSomeService(SomeService someService)
With annotation you can inject the dependency like below
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
#Component
public class CallingService {
#Autowired
protected SomeService someService ;
}
Related
Does anyone know if I should be able to use property placeholder as an expression in a Qualifier? I can't seem to get this working.
I am using spring 3.0.4.
#Controller
public class MyController {
#Autowired
#Qualifier("${service.class}")
Service service;
}
#Service
#Qualifier("ServiceA")
ServiceA implements Service {
public void print() {
System.out.println("printing ServiceA.print()");
}
}
#Service
#Qualifier("ServiceB")
ServiceB implements Service {
public void print() {
System.out.println("printing ServiceB.print()");
}
}
XML:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="file:/etc/config.properties"/>
</bean>
config.properties:
config.properties
service.class=serviceB
This works. You can leave off the service names if you just use the default spring bean name. serviceA vs ServiceA, etc.
#Controller
class MyController {
#Autowired(required=false)
#Qualifier("Service")
Service service;
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("app-ctx.xml", MyController.class);
for(String s:context.getBeanDefinitionNames()){
System.out.println(s);
for(String t:context.getAliases(s)){
System.out.println("\t" + t);
}
}
context.getBean(MyController.class).service.print();
}
}
public interface Service {
void print();
}
#Service(value="ServiceA")
public class ServiceA implements example.Service {
public void print() {
System.out.println("printing ServiceA.print()");
}
}
#Service(value="ServiceB")
public class ServiceB implements example.Service {
public void print() {
System.out.println("printing ServiceB.print()");
}
}
XML:
<beans>
<alias name="${service.class}" alias="Service"/>
<context:property-placeholder location="example/app.properties"/>
<context:component-scan base-package="example"/>
<beans>
Props:
service.class=ServiceB
This solution works without XML and with properties file.
Yours classes improved:
MyController.java:
#Controller
public class MyController {
#Autowired
public MyController(#Qualifier("MyServiceAlias") MyService myService) {
myService.print();
}
}
ServiceA.java:
#Service("serviceA")
public class ServiceA implements MyService {
#Override
public void print() {
System.out.println("printing ServiceA.print()");
}
}
ServiceB.java:
#Service("serviceB")
public class ServiceB implements MyService {
#Override
public void print() {
System.out.println("printing ServiceB.print()");
}
}
application.properties (here you can change which class will be loaded):
service.class=serviceA
And important configuration file AppConfig.java:
#Configuration
public class AppConfig {
#Autowired
private ApplicationContext context;
#Bean
public MyService MyServiceAlias(#Value("${service.class}") String qualifier) {
return (MyService) context.getBean(qualifier);
}
}
Additional explanations:
Use #Qualifier only for field which will be autowired. For services, to specify bean name, use #Service.
If you want standard bean name you don't need to use #Service with specyify name. For example, standard bean name for ServiceA is serviceA (not ServiceA - see big first letter), so #Service("serviceA") redundant (#Service is enough).
I based AppConfig on this answer: Spring Bean Alias in JavaConfig.
This solution is better than this Spring Qualifier and property placeholder, because you don't need XML.
Tested on Spring Boot 1.5.7.
I would venture to guess the answer is no, just based on the write ups in a few javadoc pages. For example, see the docs for #Value:
http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/annotation/Value.html
Notice they make special mention of using expressions in the annotation. For comparison, the docs for #Qualifier:
http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/beans/factory/annotation/Qualifier.html
Which make no mention of expressions. Obviously not a definitive answer (but spring is generally very good on documentation). Also, if expressions were supported in the #Qualifier annotation I would expect they work the same way as the #Value annotation (just based on spring being a very consistent framework).
Spring 3.1 has the new profile bean feature, which seems like it can accomplish something like what you're trying to do. Here's a write up for that:
http://blog.springsource.com/2011/02/14/spring-3-1-m1-introducing-profile/
As a workarround, you can set the desired Spring service implementation based on its name in your config.properties.
#Controller
public class MyController {
//add a String which will hold the name of the service to implement
#Value("${service.class}")
private String serviceToImplement;
Service service;
// now autowire spring service bean based on int name using setter
#Autowired
public void setService(ApplicationContext context) {
service = (Service) context.getBean(serviceToImplement);
}
}
#Service
#Qualifier("ServiceA")
ServiceA implements Service {
public void print() {
System.out.println("printing ServiceA.print()");
}
}
#Service
#Qualifier("ServiceB")
ServiceB implements Service {
public void print() {
System.out.println("printing ServiceB.print()");
}
}
config.properties
service.class=serviceB
Maybe give this a whirl:
#Controller
public class MyController {
private String serviceId;
#Value("${serviceId}")
public void setServiceId(String serviceId) {
this.serviceId = serviceId;
}
#Autowired
#Qualifier(serviceId)
Service service;
}
I am new to Spring. I have at work in spring-config.xml this :
<bean id="statusEmailSender" class="my.package.email.StatusEmailSenderImpl">
<property name="mailSender" ref="mailSender"/>
<property name="templateMessage" ref="templateMessage"/>
</bean>
In some classes already defined I see something like this:
#Autowired
private StatusEmailSender statusEmailSender;
And it works. When I do it in my own class, I get a NullPointerException.
I know the reason: I am creating my class with new():
return new EmailAction(config,logger);
My class looks like this:
public class EmailAction{
#Autowired
StatusEmailSender statusEmailSender;
public EmailAction(...)
{
...
}
}
Do you know how I can get around this? This is legacy code, and it's extremely difficult to get around the new EmailAction() call.
You want use a spring bean inside a non-spring class(legacy code). In order to do that you need to make the Spring's ApplicationContext (which holds BeanFactory where spring beans are residing) available to legacy code.
For that you need to create a spring bean something like:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
and define this bean inside your Spring configuration file (or if you are using annotation driven, annotate bean with #Component)
<bean id="springContext" class="com.util.SpringContext />
Since SpringContext exposes a static method, the legacy code can access it.for example if the legacy code needs spring bean EmailAction, call like:
EmailAction emailAction= (EmailAction)SpringContext.getApplicationContext.getBean(EmailAction.class);
now the emailAction will contain all its dependencies set.
Why don't you just autowire your EmailAction class when you need it?
EmailAction.java:
#Component
public class EmailAction{
// ...
}
WhereYouNeedIt.java:
public class WhereYouNeedIt{
#Autowired
EmailAction emailAction;
// access emailAction here
}
Hopefully someone might have the answer for this problem.
I have a autowire problem occuring when I run my tests but not else.
The exception is pretty clear as it says 'myField' is missing. The field is however inherited from a base class. I cannot find the answer to my problem anywhere so I will try my luck here.
The exception
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'myService': Injection of autowired dependencies failed;
nested exception is java.lang.NoSuchFieldError: myField
My base class
public abstract class CommonStuff {
protected String myField; // the one thats gone missing
public abstract void setMyField(String myField);
}
My service
#Service("myService")
public class MyService extends CommonStuff {
#Value("${myProperty.myField}")
public void setMyField(String myField) {
this.myField = myField;
}
...
}
My controller
#Controller
public class MyController {
#Autowired
private MyService myService;
public void setMyService(MyService myService) {
this.myService = myService;
}
...
}
My application-context.xml
Nothing seems to be left out.
<context:component-scan base-package="com.myapp" />
<bean
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
<property name="ignoreResourceNotFound" value="true" />
<property name="locations">
<list>
<value>classpath:my.properties</value>
<value>classpath:myother.properties</value>
</list>
</property>
</bean>
my.properties
myProperty.myField=some value
My test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:application-context.xml" })
public class MyControllerTest {
#Autowired
MyController myController;
#Mock
MyService myService;
#Test
public void myServiceTest() {
// do stuff with myService
}
...
}
The problem
As I mentioned the code runs fine but a spring has trouble autowiring whenever I try to run the test.
The problem is not the test but the wiring when starting the test. Somehow spring cannot find myField from the abstract CommonStuff class so it says that MyService do not have the field.
If needed I can post the full stacktrace but I think the essense of the exception is already here.
I gave up and moved the myField back into the service and skipped the setMyField.
This is how it is now.
Base class
public abstract class CommonStuff {
public abstract String getMyField();
public void doCommonStuff() {
// use getMyField()
}
}
My service
#Service("myService")
public class MyService extends CommonStuff {
#Value("${myProperty.myField}")
private String myField;
#Override
public String getMyField() {
return myField;
}
...
}
This solves what I wanted since I now have access to myField from CommonStuff.
I'm doing some coding with Java + Spring. Something like,
public interface PeopleService {}
public class CustomerService implemented PeopleService {}
public class EmployeeService implemented PeopleService {}
Once if I use #Autowired in the code like this,
#Autowired
protected PeopleService peopleService;
The application throws exception of "no unique bean of type [xxxxxxxx] is defined: expected single matching bean but found 2." during the runtime. The problem can be easily fixed by adding #Qualifier("xxxxxx"). However, the annoying part of this problem is that the exception only pops up during the runtime. By which means, if I don't check the annotation carefully before hand manually. it could throw the exception once the application hit the autowired point.
I'm not a fan of manual checking. Just wonder, is there any smart way of testing/detecting such exception before running the application (e.g. during the initialization of the application, or compiling)?
Many thanks.
EDIT:
At the end, I just came up the solution which does a test that will find all classes that extends BasicService, and initialize them one by one to test the uniqueness of autowired beans within each class.
#Test
public void autowireValidationForAllSubclassOfBaseService() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(BasicService.class));
Set<BeanDefinition> serverResources = provider.findCandidateComponents("path/class");
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
for (BeanDefinition serverResource : serverResources) {
try {
Class<? extends BasicService> serverResourceClass =
(Class<? extends BasicService>) Class.forName(serverResource.getBeanClassName());
Object bean = beanFactory.createBean(serverResourceClass, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
beanFactory.initializeBean(bean, serverResourceClass.getSimpleName());
} catch (Exception e) {
Assert.assertTrue(false, "Autowired might not be handled properly " + e.getMessage());
}
}
}
This might not be the best way, but I'm happy with it for now, as it works and detects all possible autowire issue before really running it.
try to add #Service before
public class CustomerService implemented PeopleService {}
Well, you don't need to use #Autowired. You can always do explicit wiring via xml or java.
To wire the following class you could:
public class MyBean {
private PeopleService peopleService;
public MyBean(PeopleService peopleService) {
this.peopleService = peopleService;
}
}
Xml:
<bean id="customerService" class="the.package.containing.customerservice.CustomerService"/>
<bean id="employeeService" class="the.package.containing.employeeService.EmployeeService"/>
<bean id="myBean" class="the.package.containing.mybean.MyBean">
<constructor-arg ref="employeeService"/>
</bean>
Java:
#Configuration
public class AppConfig {
#Bean
public PeopleService customerService() {
return new CustomerService();
}
#Bean
public PeopleService employeeService() {
return new EmployeeService();
}
#Bean
public MyBean myBean() {
return new MyBean(customerService());
}
}
Since you seem to be after compile time type safety, I would recommend using the Java based approach, because it gives you that compile time guarantee.
At the end, I just came up the solution which does a test that will find all classes that extends BasicService, and initialize them one by one to test the uniqueness of autowired beans within each class.
#Test
public void autowireValidationForAllSubclassOfBaseService() {
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(BasicService.class));
Set<BeanDefinition> serverResources = provider.findCandidateComponents("path/class");
AutowireCapableBeanFactory beanFactory = applicationContext.getAutowireCapableBeanFactory();
for (BeanDefinition serverResource : serverResources) {
try {
Class<? extends BasicService> serverResourceClass =
(Class<? extends BasicService>) Class.forName(serverResource.getBeanClassName());
Object bean = beanFactory.createBean(serverResourceClass, AutowireCapableBeanFactory.AUTOWIRE_BY_NAME, false);
beanFactory.initializeBean(bean, serverResourceClass.getSimpleName());
} catch (Exception e) {
Assert.assertTrue(false, "Autowired might not be handled properly " + e.getMessage());
}
}
}
This might not be the best way, but I'm happy with it for now, as it works and detects all possible autowire issue before really running it.
I am a new user of spring. I am trying to achieve dependency injection by annotation. My
beans.xml is :-
<!-- Add your classes base package here -->
<context:component-scan base-package="com.springaction.chapter01"/>
<bean id="greeting" class="com.springaction.chapter01.GreetingImpl">
<property name="greeting">
<value>Naveen Jakad</value>
</property>
</bean>
bean which I want to inject is:-
package com.springaction.chapter01;
import org.springframework.stereotype.Service;
#Service
public class InjectBean {
private int id;
private String name;
public InjectBean() {
super();
}
//setter getter of above instance variables..
}
and the bean in which I want to inject above bean is :-
package com.springaction.chapter01;
import org.springframework.beans.factory.annotation.Autowired;
public class GreetingImpl implements Greeting {
private String greeting;
#Autowired
private InjectBean myBean;
public GreetingImpl() {
super();
}
public GreetingImpl(String greeting) {
super();
this.greeting = greeting;
}
public void setGreeting(String greeting) {
this.greeting = greeting;
}
#Override
public void sayGreeting() {
System.out.println(greeting + " " + myBean);
}
}
so when I test the above code by :-
BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("config.xml"));
Greeting greeting = (Greeting)beanFactory.getBean("greeting");
greeting.sayGreeting();
I get the output "Naveen Jakad null", means in nutshell I am not able to achieve my target. So please help me out and let me know where I making mistake
if you want to inject by #Autowired you don't need to config it in xml :)
You need to set
<mvc:annotation-driven />
<context:component-scan base-package="com.your.base.package" />
That way spring will know to check for annotations
With Fixus solution you do not need the xml file where you define the "greeting" bean:
Just add:
#Component // or #Service if it's also a service
public class GreetingImpl implements Greeting {
This way you do not need to define your beans in the xml file.
If you use Junit test, you just inject the class to test (e.g "Greeting") in your MyJunitClass and have your context set to the one with the annotation-driven and component -scan definition.
You can see that doc to configure your JUnit tests:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/testing.html#integration-testing-annotations