This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 3 years ago.
I am developing a spring boot application to send sms notification. This is my class for the purpose.
package org.otp.services;
import org.otp.Configurations;
import com.mashape.unirest.http.HttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.PropertySources;
#Component
public class SmsService
{
private static final Logger LOG = LoggerFactory.getLogger(SmsService.class);
public String send(String mobile, String msg)
{
//Code
}
}
And this is the class which uses the above class for sending notification.
package org.otp.controllers;
import org.otp.Constants;
import org.otp.services.EmailService;
import org.otp.services.SmsService;
import org.otp.dto.MessageRequest;
import org.otp.dto.MessageResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
#Component
public class MessageController {
private static final Logger LOG = LoggerFactory.getLogger(MessageController.class);
#Autowired
SmsService smsService;
public void sendMessageToAlert(#RequestBody MessageRequest messageRequest)
{
String smsStatus = "FAIL";
MessageResponse messageResponse = new MessageResponse();
//1. Nullpointer
smsStatus = smsService.send(messageRequest.getMobileNo(),messageRequest.getMessage());
}
}
Main Class
package org.otp;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
#SpringBootApplication
#EnableAsync
public class OtpServiceApplication implements ApplicationRunner
{
public static void main(String[] args) {
SpringApplication.run(OtpServiceApplication.class, args);
}
}
Problem is, I get a nullpointer exception in the (1) stating that my SmsService object is null. And my main class is in package org.otp so the two classes here falls under sub package so no need of component scan.
Therefore I am confused what to do to solve this. I have tried many answers here like adding a #Component annotation and #ComponentScan in main class but nothing works. Could someone please point out my mistake here.
Thanks in advance.
If your #Autowired annotation is not working and throws NPE ,it means that spring fails to create an instance of the component class in the application context . Try to:
Verify that the classes are in class path for scanning and also check to ensure that all auto-wired classes have the annotation #Component to enable them to be picked up during class path scanning.
Check the spring boot start up logs to verify if there are any errors
during bean creation.
Check to ensure all related classes used in the service layer are auto-wired properly and that the injected classes are annotated with #Component .
For further help please share the main application class along with your project structure.
Since you are using springboot , it is preferable to use the sprinboot stereotype annotations instead of the #Component annotation, if you are building a standard springboot web application.
#Service : for the service layer.
#Controller : for the controller layer . Also,DispatcherServlet will look for #RequestMapping on classes which are annotated using #Controller but not with #Component.
In Springboot application's main class add following annotation
#SpringBootApplication
#ComponentScan(
basePackages = {"org.otp.*"}
)
public class YourSpringMainClass{
public static void main(String[] args) {
SpringApplication.run(YourSpringMainClass.class, args);
}
}
While using annotations we should configured with #ComponentScan annotation to tell Spring the packages to scan for annotated components. This should be used in mail class(Which class wants to load first) in your case you are working with spring boot so you should use this annotation in Springboot application's main class. Like below
#SpringBootApplication
#ComponentScan(
basePackages = {"org.otp.*"}
)
public class YourSpringMainClass{
public static void main(String[] args) {
SpringApplication.run(YourSpringMainClass.class, args);
}
}
Related
So I've got a simple spring boot app, #SpringBootApplication, a stub #Configuration and a #RestController all in the same package. Spring-boot-web-starter is there and the webserver comes up fine, actuator endpoints and all. But I cannot for the life of me get the app to pick up the #RestControllers.
enter image description here
Main.class:
package com.iglossolalia.munin;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(MuninContext.class, args);
}
}
MuninContext.class:
package com.iglossolalia.munin;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
#Configuration
#EnableAutoConfiguration
public class MuninContext {
}
MuninService.class:
package com.iglossolalia.munin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class MuninService {
private static final Logger LOG = LoggerFactory.getLogger(MuninService.class);
public MuninService() {
LOG.info("Started MuninService");
}
#GetMapping("/health")
public String healthCheck() {
return "pong";
}
}
Tried explicitly adding the rest controller to the component scan with no luck there.
You have no #ComponentScan annotation in your MuninContext. Actually you can write SpringApplication.run(Main.class, args) in main method as Spring Initializr generate by default, you don't really need your context, because #SpringBootApplication work as configuration and contains #EnableAutoConfiguration, #ComponentScan, and some other annotations. Otherwise, as you pass your config class as argument in SpringApplication.run method, annotation #SpringBootApplication in Main class has no effect
I am trying to learn Spring Boot and restful application from an online tutorial. But the code I wrote for it somehow gives me an error. I have written a CommandLineRunner class like so:
package com.trial.cas.preload;
import java.util.logging.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import com.trial.cas.employee.repository.EmployeeRepository;
import com.trial.cas.employee.pojo.Employee;
#Configuration
class LoadDatabase implements CommandLineRunner {
private static final Logger log = java.util.logging.LogManager.getLogManager().getLogger("LoadDatabase");
#Autowired
EmployeeRepository employeeRepository;
#Override
public void run(String... args) throws Exception {
log.info("Preloading " + employeeRepository.save(new Employee("Bilbo Baggins", "burglar")));
log.info("Preloading " + employeeRepository.save(new Employee("Frodo Baggins", "thief")));
}
}
My EmployeeRepository class is like this:
package com.trial.cas.preload;
import org.springframework.data.jpa.repository.JpaRepository;
import com.trial.employee.pojo.Employee;
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
}
My main class is written like:
package com.trial.cas.logging.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class CASLoggingToolApplication {
public static void main(String[] args) {
SpringApplication.run(CASLoggingToolApplication.class, args);
}
}
But when I run the Spring Boot application, the lines in the run method never execute. I have a debug point point in the first line of the run method. But that never gets triggered.
Please help! Thanks in advance.
By default Spring Boot will only scan packages below the package of the main application class (in your example it would be the package com.trial.cas.logging.example and all subpackages.
You can either move the application class to a common super package for your application, or specify all other packages, that should be scanned for beans etc. on the annotation:
#SpringBootApplication(scanBasePackages = {"com.trial.cas.logging.example", "com.trial.cas.preload"})
Try using #Component instead of #Configuration when annotating your LoadDatabase class.
Also, if I recall correctly, for Spring Boot to run properly it is necessary to annotate your EmployeeRepository with #Repository.
Another last tip, try to avoid field injections like:
#Autowired
EmployeeRepository employeeRepository;
It has several drawbacks compared to constructor injection, which are described in detail in this answer: What exactly is Field Injection and how to avoid it?
Instead use constructor injection, like this:
private EmployeeRepository employeeRepository;
#Autowired
public LoadDatabase(EmployeeRepository employeeRepository){
this.employeeRepository = employeeRepository;
}
I wrote a simple set of classes to show a friend about using Annotations for AOP (instead of xml config) . We couldnt get the #ComponentScan to work AND AnnotationConfigApplicationContext getBean too misbehaves. I wanted to understand two things . See Code below :
PersonOperationsI.java
package samples.chapter3;
import org.springframework.stereotype.Component;
#Component
public interface PersonOperationsI {
public String getName();
}
PersonOperations.java
/**
*
*/
package samples.chapter3;
import org.springframework.stereotype.Component;
#Component
public class PersonOperations implements PersonOperationsI {
public String getName() {
return "";
}
}
PersonOperationsConfigClass.java
package samples.chapter3;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
//question2 - Below Component Scan didnt work - Test Case failing in setup()
//#ComponentScan(basePackages = {"samples.chapter3"})
#EnableAspectJAutoProxy
public class PersonOperationsConfigClass {
}
PersonOperationsAdvice.java
/**
*
*/
package samples.chapter3;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
#Component
#Aspect
public class PersonOperationsAdvice {
/**
* execution( [Modifiers] [ReturnType] [FullClassName].[MethodName]
([Arguments]) throws [ExceptionType])
* #param joinPoint
* #return
*/
#Before("execution(public * samples.chapter3.PersonOperations.getName()))")
public String beforeGetName(JoinPoint joinPoint) {
System.out.println("method name = " + joinPoint.getSignature().getName());
return null;
}
}
PersonOperationsTest.java
package samples.chapter3;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = { PersonOperationsConfigClass.class })
public class PersonOperationsTest {
//#Autowired
private PersonOperationsI obj;
#Before
public void setUp() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("samples.chapter3");
ctx.refresh();
obj = ctx.getBean(PersonOperationsI.class);
//obj = ctx.getBean(PersonOperations.class);//getBean of Child class not working - why ?
Assert.assertNotNull(obj);
ctx.close();
}
#Test
public void test() {
System.out.println(obj.getName());
}
}
Question1 - Why #componentscan doesnt work .If I dont use AnnotationConfigApplicationContext in test case and just rely on #componentscan & autowired - the object in test case is null
Question2 - ctx.getBean(PersonOperations.class);//getBean of Child class not working - why ?
A1 , #ComponentScan didn't work because it is commented out from the "The component classes to use for loading an ApplicationContext." or PersonOperationsConfigClass
#Configuration
//#ComponentScan(basePackages = {"samples.chapter3"})
#EnableAspectJAutoProxy
public class PersonOperationsConfigClass {}
The test class gets the ApplicationContext created from the component classes specified with the #ContextConfiguration annotation. Since no components were created or auto detected , #Autowired failed.
When AnnotationConfigApplicationContext was used within a method annotated with #Before , an ApplicationContext was programmatically created.ctx.scan("samples.chapter3"); scanned and auto-deteced PersonOperations annotated with #Component. obj reference got set with the code obj = ctx.getBean(PersonOperationsI.class);. This object was not 'Autowired'.
Update based on the comment from OP
The Junit 4 annotations and the #ExtendWith(SpringExtension.class) combination is not working for me.
Following Test class runs successfully with zero errors/failures. obj is autowired and not null. I have used the corresponding annotations from Junit 5.
package rg.app.aop.so.q1;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes= {PersonOperationsConfigClass.class})
public class PersonOperationsTest {
#Autowired
private PersonOperationsI obj;
#BeforeEach
public void setUp() {
System.out.println("init ::"+ obj);
Assertions.assertNotNull(obj);
}
#Test
public void testPersonOps() {
Assertions.assertNotNull(obj);
}
}
Configuration class
package rg.app.aop.so.q1;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan(basePackages = {"rg.app.aop.so.q1"})
public class PersonOperationsConfigClass {
}
A2,
Following are my analysis.
Remember , #EnableAspectJAutoProxy has got a default value "false" for proxyTargetClass attribute. This attribute determines the proxying mechanism : JDK proxy (false) or CGLIB proxy (true) .
Here the presence of a valid Aspect with a valid advice results in the actual proxying to kick in. A component will get proxied only when the advice has any effect on it. In short , the proxying of a Component happens only if required.
Case 1
When : #EnableAspectJAutoProxy / #EnableAspectJAutoProxy(proxyTargetClass = false )
ctx.getBean(InterfaceType) returns a bean
ctx.getBean(ImplementationClassType) fails to return a bean
Case 2
When : #EnableAspectJAutoProxy(proxyTargetClass = true )
ctx.getBean(InterfaceType) returns a bean
ctx.getBean(ImplementationClassType) returns a bean
Case 3
When : #EnableAspectJAutoProxy annotation is absent
ctx.getBean(InterfaceType) returns a bean
ctx.getBean(ImplementationClassType) returns a bean
Case 1 , Spring AOP is enabled with proxyTargetClass as false. JDK proxy creates a proxy bean of Interface type.
The bean created is of type InterfaceType and not ImplementationClassType . This explains why ctx.getBean(ImplementationClassType) fails to return a bean.
Case 2 , Spring AOP is enabled with proxyTargetClass as true . CGLIB creates a proxy bean by subclassing the class annotated with #Component.
The bean created is of type ImplementationClassType , as well qualifies as InterfaceType. So both the getBean() calls returns this bean successfully.
Case 3,
Spring only create "proxy" objects if any special processing is required ( eg: AOP , Transaction Management ).
Now with this logic , since #EnableAspectJAutoProxy is absent , a bean gets created for class annotated with #Component without any proxying.
The bean created is of type ImplementationClassType , as well qualifies as InterfaceType. So both the getBean() calls returns this bean successfully.
Analysis done with the following code.
package rg.app.aop.so.q1;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class AppMain {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.scan("rg.app.aop.so.q1");
ctx.refresh();
System.out.println();
for(String name:ctx.getBeanNamesForType(PersonOperationsI.class)) {
System.out.println(name);
}
for(String name:ctx.getBeanNamesForType(PersonOperations.class)) {
System.out.println(name);
}
PersonOperationsI obj = ctx.getBean(PersonOperationsI.class);
System.out.println(obj.getClass());
obj = ctx.getBean(PersonOperations.class);
System.out.println(obj.getClass());
ctx.registerShutdownHook();
}
}
Case 1 prints
personOperations
class com.sun.proxy.$Proxy18
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'rg.app.aop.so.q1.PersonOperations' available
Case 2 prints
personOperations
personOperations
class rg.app.aop.so.q1.PersonOperations$$EnhancerBySpringCGLIB$$c179e7f2
class rg.app.aop.so.q1.PersonOperations$$EnhancerBySpringCGLIB$$c179e7f2
Case 3 prints
personOperations
personOperations
class rg.app.aop.so.q1.PersonOperations
class rg.app.aop.so.q1.PersonOperations
Hope this helps
Usually you should use #ComponentScan along with a #Configuration annotated class and keep in mind that #ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages..
The #Component class tells Spring to create a bean of that type so you no longer need to use xml configuration, and the bean is a class that can be instantiated => no interface / abstract classes. So, in your case, you should remove the #Component from PersonOperationsI and leave it only in PersonOperations. When you annotate a class with #Component, the default name given to the bean is the class name with lower first letter, so you should call ctx.getBean("personOperationsI") or ctx.getBean(PersonOperations.class)
And for the future read these naming conventions for interfaces and implementations. In your case I would modify the following :
PersonOperationsI to Operations
Question 2
As you said, bean scanning process was not complete, so there is no bean in context and you should not expect any bean from context, Either #Autowired way or context.getBean way.(Both ways return null )
Below link has more information on bean scanning(It may help)
Spring Component Scanning
Hello im doing a simple spring application and for some reason this error came up:
Type mismatch: cannot convert from Object to AccountDAO
I have 3 classes, AccountDao:
package com.luv2code.aopdemo.dao;
import org.springframework.stereotype.Component;
#Component
public class AccountDAO {
public void addAccount() {
System.out.println(getClass() + ": DOING MY DB WORK: ADDING AN ACCOUNT");
}
}
DemoConfig:
package com.luv2code.aopdemo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
#Configuration
#EnableAspectJAutoProxy
#ComponentScan("com.luv2code.aopdemo")
public class DemoConfig {
}
And MainDemoApp:
package com.luv2code.aopdemo;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import com.luv2code.aopdemo.dao.AccountDAO;
public class MainDemoApp {
public static void main(String[] args) {
//read spring config java class
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DemoConfig.class);
//get the bean from spring container
AccountDAO theAccountDAO = context.getBean("accountDAO", AccountDAO.class); //THE PROBLE IS HERE
//call the business method
theAccountDAO.addAccount();
//close the context
context.close();
}
}
The error is in the MainDemoApp at AccountDAO theAccountDAO = context.getBean("accountDAO", AccountDAO.class);
(only the part after = is red)
Can you try this:
AccountDAO theAccountDAO = (AccountDAO) context.getBean("accountDAO", AccountDAO.class);
Try context.refresh() before context.getBean(...)call, if it does not help do following:
Annotate MainDemoApp.java with #SpringBootApplication.
Remove #ComponentScan from DemoConfig and create the #Bean explicitly.
Start in debug mode and see if hits bean creation for AccountDAO.
I kept trying to remove (and readd if nothing changed) one library from buildpath, one by one, just to try even if i dont know what effect would have. After removing org.springframework.context.jar the error disappeared.
just lol. anyone could explain please?
I have a spring boot application like this:
package my.package;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration;
#SpringBootApplication
public class MySpringBootApp{
public static void main(String[] args) {
SpringApplication.run(MySpringBootApp.class, args);
}
}
I have a service in the package my.package.service
#Service
public class MyService {
private ServiceInADifferentJar dep;
public MySerivce(ServiceInADifferentJar dep) {
this.dep = dep;
}
}
The class ServiceInADifferentJar is an #Service annotated class in a different JAR, which I include as a maven dependency.
The JAR Has this file structure:
src/main/java
- some.package.repository
MyRepository.java
- some.package.service
ServiceInADifferentJar.java
MyRepository is an #Repository annotated interface that extends a Spring Data inerface.
ServiceInADifferentJar gets MyRepository injected in its constructor.
WHen I start the application, I get an error that ServiceInADifferentJar cannot be found.
Then I added this to my SpringBootApp
#SpringBootApplication(scanBasePackages = {"some.package"})
andServiceInADifferentJar is found, but not MyRepository.
Why not? Why aren't all sub-packages of some.package in the other JAR scanned?
* EDIT *
The repository
package some.package.repository;
#Repository
public interface MyRepository extends MongoRepository<SomeEntity, String> {
}
You may want to use the EnableMongoRepositories annotation, so that your Mongo repository gets found .
#EnableMongoRepositories(basePackages = "some.package.repository")
The following question, despite being about JPA repositories, has some more explanation about how repositories scanning work :
Can't Autowire #Repository annotated interface in Spring Boot
hey man you should put this in your main class after the #SpringBootApplication tag
#ComponentScan(basePackages = {"some.package"})