I'm having trouble getting #Autowired to work in a class annotated by #Service, the autowired variable always is null. Let me explain:
#Service
public class Searcher extends Thread implements ISearcher {
#Autowired
protected ISessionProvider sessionProvider; <-- always null
...
public Searcher() {
sessionProvider.doSomeStuff();
}
sessionProvider here is always null.
The strange thing is that the same autowire in a #Controller does work:
#Controller
#RequestMapping("/search")
#Secured({ "ROLE_USER" })
public class SearchController extends BaseController {
#Autowired
protected ISessionProvider sessionProvider; <-- does work
#Autowired
protected ISearcher searcher;
The last line throws exception because the constructor of Searcher (implementing ISearcher) tries to access sessionProvider, which is null.
I am not sure what i might be doing wrong, it looks like spring doesn't autowire the ISessionProvider in Searcher.
It might be that spring first autowires the Searcher in SearchController, but it should first autowire SessionProvider in Searcher and next autowire Searcher in SearchController. Cause searcher cannot be autowired without a valid SessionProvider. Puzzles my brain ;-)
Can somebody offer a helping brain?
[edit]
component-scan includes my services, controllers and everything, just checked.
the I before interfaces is indeed not very nice (old habits)
not sure if this is a "duplicate" question, mainly because i'm not doing anything with "new", i let do spring do all the hard work, but i'll take a better peek.
Spring will first create the bean instance, then inject the beans. You're trying to access to the injected bean when the current bean is created, thus the bean will be null. That's default behavior.
If you want/need to execute any logic after creating the bean, use #PostConstruct decorated method, which is invoked after the bean has been created and all the dependencies injected. Here's a sample:
#Service
public class Searcher extends Thread implements ISearcher {
#Autowired
protected ISessionProvider sessionProvider;
public Searcher() {
//nothing should be here...
}
#PostConstruct
public void init() {
sessionProvider.doSomeStuff();
}
}
Spring can only do dependeny injection after the bean has been constructed. You are calling the method in the constructor and at that point the ISessionProvider hasn't been injected yet and hence it is null which in turn leads to a nice NullPointerException.
You have 2 solutions
Move the code from the constructor to a method annotated with #PostConstruct
Change the default no-arg constructor to take an argument and use that to do dependeny injection instead of the #Autowired field.
Solution 1: move that code to a method annotated with #PostConstruct.
#Service
public class Searcher extends Thread implements ISearcher {
#Autowired
protected ISessionProvider sessionProvider;
...
public Searcher() {}
#PostConstruct
public void init() {
sessionProvider.doSomeStuff();
}
Solution 2: Use constructor based dependency injection.
#Service
public class Searcher extends Thread implements ISearcher {
protected final ISessionProvider sessionProvider;
#Autowired
public Searcher(ISessionProvider sessionProvider) {
this.sessionProvider=sessionProvider;
sessionProvider.doSomeStuff();
}
}
I didn't do test, but I think the problem is, in class Searcher, you created a no-argument constructor, and there you used the "autowired" bean. I guess there you would get NPE. Since spring would instantiate your Searcher using default constructor (by reflection) if you didn't specify one, that is, it will use the no-argument constructor you created, but at this moment, the "autowired" bean was not yet injected.
If you want to do something immediately after the bean was instantiated, you can wrap the logic code in a method, and annotate it with #PostConstruct.
I am also getting the same issue but i cannot use #PostConstruct because i am not using doinit. I have a simple method which is getting the language from lang service.
My lang service is null here but in another controller it is not null, it is getting autowired.
#Service
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
public class FormSelectLanguageHandler extends SimpleTagSupport {
#Autowired
private LangService langService;
public List<Lang> getLanguages(){
Sessions session = (Sessions) getJspContext().findAttribute("SHLSESSION");
List<Lang> languages=new ArrayList<Lang>();
//List<Lang> allLanguages = langService.findAllLangs();
List<Lang> all =new ArrayList<Lang>();
if (isRenderLangLabel()) {
all = langService.findByDisplayOrderAsc();
} else {
all = langService.findByNameOrderByNameAsc();
}
Long companyId = (null == session || null == session.getCompany())? null:session.getCompany().getId();
}
}
Related
the below bean of Class I want to inject in other non-managed bean, but it is not working as expected
#Component
#Setter
#Getter
public class AbstractLayoutProperties {
#Value("${spring.application.name}")
private String appName;
#Autowired
S3Service s3Service;
#Autowired
S3Client s3Client;
}
Below is the class which is not managed by the spring, but I am using #Configurable
#Configurable(preConstruction = true, autowire = Autowire.BY_NAME)
#EnableSpringConfigured
public class OverlayServiceImpl
implements GenericVehicleOverlayService<T, R> {
public findOnlyActive(){
appName = layoutProperties.getAppName(); // throwint NullPointerException beacuse the object not injected properly
}
#Autowired
AbstractLayoutProperties layoutProperties;
}
One more point, findOnlyActive method I am not calling directly, I am calling this from another service, lets say
#Service
public class OtherService{
public void findActive(){
OverlayServiceImpl impl=new OverlayServiceImpl();
impl.findOnlyActive();
}
#Autowired
OtherRepository otherRepo;
}
Problem statrement:
when impl.findOnlyActive(); is executed, it should inject all the required beans inside OverlayServiceImpl. In the same class I have two beans which are autowired, it seems none of them injected, this is the reaosn that every time I am encountering Nullpointer exception. so my question is how do I make it work, what are the steps and action I need to take so that spring will inject the dependencies in non managed object i,e OverlayServiceImpl.
To avoid the Spring context reloading again and again, I have moved #MockBean annotated injection to a parent class, something like this.
#SpringBootTest
.......
public abstract BaseTest {
#MockBean
protected OneService oneService;
This serves the test classes which need a mock for OneService. However, for the test that I would like also extended from BaseTest, but inject the real OneService via #Autowired will not work, as it will inherit the mock injection from the BaseTest.
public AnotherTest extends BaseTest {
#Autowired
protected OneService oneService;
Even I used #Autowired annotation, the oneService field will be the mock instance inherited from BaseTest.
Is there a way I can force inject to use autowired?
In Java there is technically no way to override a field. When you declare a field with the same name in a subclass, that field shadows the field with the same name in the superclass. So that is one hurdle.
The second hurdle stems from the fact that there is no way in Spring Boot's testing support to turn off mocking of a bean in a subclass if the superclass configures the mocking via #MockBean.
Thus, the solution is to invert what you are trying to do by having the real bean injected via #Autowired in the superclass and then turn on mocking for the specific bean type in the subclass.
Declare the #Autowired field in the superclass but do not redeclare the field in the subclass.
Declare #MockBean at the class level in the subclass, specifying which classes (i.e., bean types) to be mocked.
That last step results in the inherited field being injected with a mock in the subclass.
The following two classes demonstrate this technique in practice.
#SpringBootTest(classes = BaseTests.Config.class)
class BaseTests {
#Autowired
protected Service service;
#Test
void service() {
assertThat(service.getMessage()).isEqualTo("real");
}
#Configuration
static class Config {
#Bean
Service service() {
return new Service();
}
}
static class Service {
String getMessage() {
return "real";
}
}
}
#MockBean(classes = BaseTests.Service.class)
class MockBeanTests extends BaseTests {
#BeforeEach
void setUpMock() {
when(service.getMessage()).thenReturn("mock");
}
#Test
#Override
void service() {
assertThat(service.getMessage()).isEqualTo("mock");
}
}
I have Service class and Repository interface (Spring Data). I have also one abstract class:
public abstract class TestingMethod {
public TestingMethod() {
timeSum = 0;
}
protected long timeSum;
}
And class that extends it:
#Component
public class LimitTestingMethod extends TestingMethod {
#Autowired
private GeoTestDataRepository geoTestDataRepository;
private final int limitSize;
public LimitTestingMethod(int limitSize) {
super();
this.limitSize = limitSize;
}
}
In my Service I want to create instance of LimitTestingMethod and set its argument limitSize.
Something like:
LimitTestingMethod ltm3 = new LimitTestingMethod(3);
LimitTestingMethod ltm10 = new LimitTestingMethod(10);
But I got error:
Description: Parameter 0 of constructor in
com.exence.postgiscma.testingMethod.LimitTestingMethod required a bean
of type 'int' that could not be found. Action: Consider defining a
bean of type 'int' in your configuration.
Is that possible to achieve something like I want?
All best!
//EDIT
As I can see in comments it's bad approach. So maybe someone will give me advise how to project this better?
Is this good solution to pass repo as argument in constructor (I guess that not, but I can't get the idea how to do this better)?
LimitTestingMethod ltm3 = new LimitTestingMethod(3, geoTestDataRepository);
Is there a good and elegant solution?
As you are creating instances outside the scope of Spring your current solution won't work. The error comes from the fact that you have annotated it with #Component, it will detect it at startup and tries to create a bean, and fails.
To solve this you can do 1 of 2 things.
Let Spring handle the creation of the beans by using the ApplicationContext as a factory, providing additional arguments and make the bean prototype scoped.
Let Spring handle the injection after you manually created the instance using the ApplicationContext.
Use ApplicationContext as a factory
First make your bean a prototype so that it will be constructed when needed.
#Component
#Scope(
ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class LimitTestingMethod extends TestingMethod { ... }
Now an instance won't be created during startup. In your service inject the ApplicationContext and use the getBean method to get your desired instance.
public class Service {
#Autowired
private ApplicationContext ctx;
public void yourMethod() {
LimitTestingMethod ltm3 = ctx.getBean(LimitTestingMethod.class, 3);
LimitTestingMethod ltm10 = ctx.getBean(LimitTestingMethod.class, 10);
}
}
This will let Spring create the instance using the value passed in for the constructor and do the autowiring.
Injection after creation
Another solution is to manually create the instances and after that let Spring handle the auto wiring. You will lose the AOP abilities with this and will get only auto wiring.
First remove the #Component annotation from your LimitTestingMethod so it won't get detected during startup.
public class LimitTestingMethod extends TestingMethod { ... }
Now in your service autowire the ApplicationContext and after creating your bean use that to inject the dependencies.
public class Service {
#Autowired
private ApplicationContext ctx;
public void yourMethod() {
LimitTestingMethod ltm3 = new LimitTestingMethod(3);
LimitTestingMethod ltm10 = new LimitTestingMethod(10);
ctx.getAutowireCapableBeanFactory().autowireBean(lmt3);
ctx.getAutowireCapableBeanFactory().autowireBean(lmt10);
}
}
Both will achieve what you want, however, now your code directly depends on the Spring API. So instead of doing this, you are probably better of with another option and that is to inject everything for the LimitTestingMethod through the constructor and pass the repository yourself.
Use constructor to create an instance
public class LimitTestingMethod extends TestingMethod {
private final GeoTestDataRepository geoTestDataRepository;
private final int limitSize;
public LimitTestingMethod(int limitSize, GeoTestDataRepository geoTestDataRepository) {
this.limitSize=limitSize;
this.geoTestDataRepository=geoTestDataRepository;
}
}
Then you can simply autowire the repository in your service class and create the instances as needed (or create a factory which contains the complexity of creating this object).
public class Service {
#Autowired
private GeoTestDataRepository repo;
public void yourMethod() {
LimitTestingMethod ltm3 = new LimitTestingMethod(3, repo);
LimitTestingMethod ltm10 = new LimitTestingMethod(10, repo);
}
}
I'm relatively new to Spring, and I'm trying to understand an issue I'm experiencing in which a dependency is not being autowired into a bean that is the parent of another bean that is being constructed.
The parent class is specified as follows. Note that I've abbreviated some of the logic for clarity. The Log class is implemented as an entity.
#Component
#Scope("prototype")
public class AppTransaction {
private String componentName;
#Autowired
private LogRepository logRepository;
public AppTransaction(String componentName) {
this.componentName = componentName;
}
public void writeLog(String logText) {
Log log = new Log(this.componentName, logText);
this.logRepository.save(log);
}
}
The child class is implemented as follows.
#Component
#Scope("prototype")
public class EmployeeJobTransaction extends AppTransaction {
#Autowired
private EmployeeRepository employeeRepository;
private String componentName;
private String jobName;
public EmployeeJobTransaction(String componentName, String jobName) {
super(componentName);
this.jobName = jobName;
}
public List<String> doJob() {
List<String> statuses = this.employeeRepository.getEmployeeJobStatuses();
writeLog("Job complete.");
}
}
In my service class, I'm using the application context to get an instance of the EmployeeJobTransaction bean. I'm doing this because the input parameters to the EmployeeJobTransaction bean are based on user input.
#Service
public class JobServiceImpl {
#Autowired
private ApplicationContext applicationContext;
public void initJob() {
EmployeeJobTransaction employeeJobTransaction = this.applicationContext.getBean(EmployeeJobTransaction.class, "EmployeeComponent", "CheckEmployeeJobStatus");
jobTransaction.doJob();
}
}
When I get the EmployeeJobTransaction bean, the EmployeeRepository bean is autowired as expected. However, the AppTransaction instance created does not appear to be a Spring-managed bean because the LogRepository object that has been autowired is null. I'm assuming this is because the call to super() in the EmployeeJobTransaction class does not create an instance of AppTransaction as a Spring-managed bean.
What are my options? Must I autowire the LogRepository bean into the EmployeeJobTransaction class and then pass it to the writeLog method as a parameter? I'm not understanding why the parent class is not created as a Spring bean when the child class is created as such.
For those that may come across this question in the future, I understand now that I was interpreting what Spring was doing incorrectly.
I turned on debugging and had set a breakpoint in the AppTransaction constructor.
public AppTransaction(String componentName) {
this.componentName = componentName; //Breakpoint here
}
When I executed my logic, I was confused because the autowired LogRepository bean was null.
According to the Spring documentation:
Fields are injected right after construction of a bean, before any config methods are invoked.
Therefore, it makes sense that the LogRepository bean is null in the constructor. When the writeLog method is called, the LogRepository bean is not null because it was successfully autowired AFTER the construction of the AppTransaction bean.
Thanks to those who responded.
TLDR: Autowired fields are null inside the constructor of a bean. The beans are not autowired until the construction of the bean in which they are referenced has completed.
I think you are a littel confused. I will try to explain me:
Your code shows 3 Spring beans:
AppTransaction
With an autowired dependency of the logRepository
EmployeeJobTransaction
With an autowired dependency of the employeeRepository
With an autowired dependency of the logRepository (inhereted of the parent class AppTransaction)
JobServiceImpl
When you call to he super method on EmployeeJobTransaction you are not calling to AppTransaction bean. You are calling to the parent class constructor method.
Is unnecessary to have a Spring bean of the AppTransaction class (remove the Component and Scope annotations of this class)
When you call to getBean method, Spring create a new bean each time. I think this is unnecessary. You could declare EmployeeJobTransaction bean as singleton (remove de Scope annotation) and to add the componentName and jobName attributes as parameters of doJob method.
I think woult be the best way.
This is my current scenario:
#WebListener
public class WebListenerService implements HttpSessionListener{
.... implement methods
#Produces
#Dependent
public SessionDependentService sessionDependentService(){
}
}
#SessionScoped
#Named
public class AccountController implements Serializable{
//Injected properly and works as expected
#Inject
private SessionDependnetService sessionDependentService;
#Inject
#OnLogin
private Event<Account> accountEvent;
public void onLogin(){
accountEvent.fire(authenticatedAccount);
}
}
#SessionScoped
public class AccountObserver implements Serializable{
//This does not work. It is always null.
#Inject
private SessionDependnetService sessionDependentService;
public void onLoginEvent(#Observes #OnLogin final Account account) {
//When this methods is invoked
//the sessiondependentservice is always null here.
}
}
In the AccountController, the SessionDependentService is correctly injected and is not null, while in the AccountObserver, it is always null.
EDIT:
Event using the parameter injection still results to a null value.
public void onLoginEvent(#Observes #OnLogin final Account account, final SessionDependnetService sessionDependentService) {
//When this methods is invoked
//the sessiondependentservice is always null here.
}
Netbeans correctly highlights this as an injection point.
Why is this the case?
I am using wildfly 8 server.
I changed the producer bean from SessionScoped to Stateless bean:
#Stateless
public class WebListenerSessionService {
//Use Instance since http session are dynamic.
#Inject
private Instance<HttpSession> httpSession;
#Produces
#Dependent
public SessionDependentService sessionDependentService(){
//use session to lookup existing service or produce a new one.
}
}
Even though this works fine, there is no where in the CDI spec which says Producer method must be session beans.
to quote:
A producer method must be a default-access, public, protected or private, non-abstract method
of a managed bean class or session bean class. A producer method may be either static or non-
static. If the bean is a session bean, the producer method must be either a business method of
the EJB or a static method of the bean class.
And since #SessionScoped is a managed bean class, why would it an injection into an observer bean not work.