This question already has answers here:
Why is my Spring #Autowired field null?
(21 answers)
Closed 4 months ago.
Note: I'm updating this since I've found a solution.
This question is similar to Why is my Spring #Autowired field null?, but I'm using the main() method here. The solution is to mark Foo with #Component and autowire it into Main through a #PostConstruct method. I learned about this through How to use autowired (#Autowired) references from main(String[] args) method?
On PostContruct: Why use #PostConstruct?
#PostConstruct makes sure all beans are fully initialized before executing (including the bean class you're actively editing).
But the bigger issue was me doing Foo foo = new Foo(). foo is outside the scope of Spring's context and 100% of it's lifecycle is managed by me. Put everything back in Spring's hands by autowiring everything:
New Main.java
package org.example;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.PostConstruct;
#SpringBootApplication
public class Main {
#Autowired
Foo foo;
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
#PostConstruct
public void test() {
foo.message();
}
}
New Foo.java
package org.example;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
#Component
#Slf4j
public class Foo {
#Autowired
Bar bar;
public Foo() {
log.info("Foo bean created");
}
public void message() {
log.info(bar.getWord());
}
}
The original question is below:
I've followed so many Spring tutorials that do it this way, and it never works on my end. No clue what I'm doing wrong, but I seriously need help figuring this out.
Main.java
package org.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
#ComponentScan
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
Foo foo = new Foo();
foo.message();
}
}
Foo.java
package org.example;
import org.springframework.beans.factory.annotation.Autowired;
public class Foo {
#Autowired
Bar bar;
public void message() {
System.out.println(bar.getWord());
}
}
Bar.java
package org.example;
import org.springframework.stereotype.Component;
#Component
public class Bar {
String word = "word";
public String getWord() {return word;}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>untitled</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.7.5</version>
</dependency>
</dependencies>
</project>
When running from Main(), I get:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "org.example.Bar.getWord()" because "this.bar" is null
at org.example.Foo.message(Foo.java:11)
at org.example.Main.main(Main.java:14)
These are all in the same directory/package. I've been at this for two hours and have no clue why this isn't working. Any help on this would be greatly appreciated.
What I tried:
Using #Autowired to create a bean that I can use in another class.
What I expected to happen:
The String word to be printed to the console.
My understanding is that a class that has #Component is up for grabs by Spring to be a bean if you're using #Autowired to inject it. I have met that criteria and I am not getting my expected result.
What actually resulted:
A NullPointerException
Autowired only works when you inject the component. You will have to make Foo a component (or define a bean) too and Autowire that into your main class for this to work. Alternatively, you can use an instance of the ApplicationContext.
You also don't need that #ComponentScan annotation since the #SpringBootApplication already has it.
See: https://docs.spring.io/spring-boot/docs/2.0.x/reference/html/using-boot-using-springbootapplication-annotation.html
Related
I'm new in spring-boot, and have spring-boot desktop test project with weird names, based on another example. The error given is:
`***************************
APPLICATION FAILED TO START
Description:
Parameter 0 of constructor in com.test_4.test4.NonWebService required a bean of type 'com.test_4.test4.RandomTableREPO' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'com.test_4.test4.RandomTableREPO' in your configuration.`
And here are my classes:
**Test4Application**
package com.test_4.test4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class Test4Application implements ExecuteI {
#Autowired
private NonWebService service;
public static void main(String[] args) {
SpringApplication.run(Test4Application.class, new String[]{"one_arg", "sec_arg"});
}
#Override
public void run(String[] args) throws Exception {
service.save(new String[] {"dummy_str", "dummy_str"});
}
}
**ExecuteI**
package com.test_4.test4;
import org.springframework.boot.CommandLineRunner;
public interface ExecuteI extends CommandLineRunner {
void run(String... args) throws Exception;
}
**NonWebService**
package com.test_4.test4;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class NonWebService {
private final RandomTableREPO randomTableREPO;
#Autowired
public NonWebService(RandomTableREPO randomTableREPO) {
this.randomTableREPO = randomTableREPO;
}
public void save(String... dummyArgs) {
this.randomTableREPO.save(new RandomTableEntity());
System.out.println("\n\n+++++++++++++++++++++++++++++++++++++");
}
}
**RandomTableREPO**
package com.test_4.test4;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface RandomTableREPO extends JpaRepository<RandomTableEntity, Integer> {
}
**application.properties**
spring.main.web-application-type=none
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://localhost:5432/test3
spring.datasource.username=postgres
spring.datasource.password=
spring.jpa.show-sql=true
have also RandomTableEntity.class, but i think for the described problem is not neccesary.
I accessed several links, but I still didn't find an answer to my error.
Until i've created and tried to use RandomTableREPO, i reached the save() method in NonWebService.class, but couldn't insert an object in database... any help from the enlightened minds in spring boot?
I want to have an object saved in database, using RandomTableREPO interface, which extends JpaRepository
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'm trying to connect my Controller to Repository in one of the spring application but I'm getting an error saying "Field tweetRepository in TweetsController.TweetsController required a bean of type 'TweetsController.TweetRepository' that could not be found."
Can someone help me with this? Thanks in advance. I've attached code samples as well.
TwitterApplication.java
package SpringMVC.Twitter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#ComponentScan("AuthController")
#ComponentScan("TweetsController")
public class TwitterApplication {
public static void main(String[] args) {
SpringApplication.run(TwitterApplication.class, args);
}
}
TwitterController.java
package TweetsController;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Optional;
#RestController
public class TweetsController {
#Autowired
private TweetRepository tweetRepository;
#RequestMapping("/tweets")
public Iterable<TweetsContent> getAllTweets() {
return tweetRepository.findAll();
}
#RequestMapping("tweet/{id}")
public Optional<TweetsContent> getTweet(#PathVariable int id) {
return tweetRepository.findById(id);
}
#RequestMapping(method = RequestMethod.POST, value = "/tweets")
public boolean addTweet(#RequestBody TweetsContent tweet) {
TweetsContent t = tweetRepository.save(new TweetsContent(tweet.getTitle(), tweet.getContent()));
if (t != null)
return true;
else
return false;
}
}
TwitterRepository.java
package TweetsController;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
#Repository
public interface TweetRepository extends CrudRepository<TweetsContent, Integer> { }
Add the spring data dependency on your pom:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Add this too.
#ComponentScan("TweetRepository")
You don't need to use #ComponentScan("AuthController") and #ComponentScan("TweetsController") because if you use #SpringBootApplication, scanning will occur from the package of the class that declares this annotation. But you need to put TwitterApplication like this:
You don't have to specify #ComponentScan in your TwitterApplication, because spring boot application is scanning its own directory at the startup. and remove the #Repository
annotation from your repository class, it is also not needed.
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);
}
}
I want to be able to track methods that are anotated with #RequestMapping that are annotated with a certain annotation (for instance #LooseController).
I have two pointcuts: requestMappings() and looseController()
this works well if the method that is annotated with #RequestMapping is in a class that has #LooseController but not if the #LooseController is in a subclass
for instance, when update(id) is called on Controller1 it is not caught by this aspect
Update to include more information:
package de.scrum_master.app;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class MyAspect {
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
private static void requestMapping() {}
#Pointcut("#within(de.scrum_master.app.LooseController)")
private static void looseController() {}
// #Pointcut("#this(de.scrum_master.app.LooseController)")
// private static void looseController() {}
#Before("requestMapping() && looseController()")
public void myAdvice(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestMapping;
//#LooseController
public abstract class PutController {
#RequestMapping("/{id}")
public void update(String id) {
}
}
package de.scrum_master.app;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
#Retention(RUNTIME)
public #interface LooseController {
}
package de.scrum_master.app;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
#Component
#LooseController
#RequestMapping("/something")
public class Controller1 extends PutController {
}
package de.scrum_master.app;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
#SpringBootApplication
public class AspectApplication implements CommandLineRunner {
#Autowired
private Controller1 controller1;
#Autowired
private ConfigurableApplicationContext context;
public static void main(String[] args) {
SpringApplication.run(AspectApplication.class, "--logging.level.root=WARN", "--spring.main.banner-mode=off");
}
#Override
public void run(String... strings) throws Exception {
controller1.update("test");
context.close();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>aspects</groupId>
<artifactId>aspects</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
</project>
As I said in my comment, I have to speculate:
It begins with your exact pointcut (which you do not show)
and goes on with the question whether you use Spring AOP or full AspectJ via LTW (load-time weaving).
In the former case you do not explain if your target classes are actual Spring beans because Spring AOP can only proxy Spring beans/components.
In the latter case you have more options but have to configure your application in a different way.
You also do not show your own annotation's implementation, especially not if it has the required runtime retention.
My hypothesis for now is that
you use proxy-based Spring AOP and
all classes and aspects are #Components or otherwise declared as Spring beans in your configuration.
But in order to show you what happens I will use a stand-alone Java example with AspectJ, not a Spring application. I only put spring-web.jar and sprint-context.jar on my classpath so as to resolve the Spring annotations.
Annotation:
package de.scrum_master.app;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface LooseController {}
Abstract base class:
package de.scrum_master.app;
import org.springframework.web.bind.annotation.RequestMapping;
public abstract class PutController {
#RequestMapping("/{id}")
public void update(String id) {}
}
Subclass + main method:
package de.scrum_master.app;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;
#Component
#LooseController
#RequestMapping("/something")
public class Controller1 extends PutController {
public static void main(String[] args) {
new Controller1().update("foo");
}
}
The aspect which I guess you might use:
Please note that your own pointcut within(#blabla.LooseController) is syntactically invalid, this is why I changed it to #within(blabla.LooseController).
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class MyAspect {
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
private static void requestMapping() {}
#Pointcut("#within(de.scrum_master.app.LooseController)")
private static void looseController() {}
#Before("requestMapping() && looseController()")
public void myAdvice(JoinPoint thisJoinPoint) {
System.out.println(thisJoinPoint);
}
}
Console log when running Controller1.main:
staticinitialization(de.scrum_master.app.Controller1.<clinit>)
call(void de.scrum_master.app.Controller1.update(String))
Now you see the problem: AspectJ can intercept a few joinpoints for the given pointcut, but neither call nor staticinitialization are supported by Spring AOP according to the documentation.
So either you need to switch to AspectJ with LTW or devise another pointcut strategy.
To be continued, I have to interrupt the answer here for a while because I have an appointment, but will add some more info later.
Update: Okay, here is your problem and a solution: #within(de.scrum_master.app.LooseController) looks inside classes with the #LooseController annotation, but the parent class with the annotated method you are trying to intercept does not have that annotation. Thus, #within() is not the right pointcut type for you. What you want to express is that the instance, i.e. the current target object upon which the method is called, belongs to an annotated class. Therefore, you need a #target() pointcut:
#Pointcut("#target(de.scrum_master.app.LooseController)")
private static void looseController() {}
Alternatively you could also use this workaround (a little ugly, but works too):
#Pointcut("target(#de.scrum_master.app.LooseController Object)")
private static void looseController() {}
Now the console log says:
execution(void de.scrum_master.app.PutController.update(String))
This should also work in Spring AOP because execution() is a supported pointcut type there.