1

I was trying to update the table row data from outside the controller (Inside some threads) and getting 'NullPointerException' always.

Thread code:

public class S3Thread implements Runnable {

@Autowired  
private IAutomationService automationService;

@Override
public void run() { 
    Automation config = new Automation("user1","success");
    automationService.updateAutomation(config);
 }
}

NullPointer exception thrown on below line: automationService.updateAutomation(config);

Note: I was able to create/update from the controller class.Only in Thread.

4 Answers4

1

Well, this is the classical Why is my Spring @Autowired field null case. You create the S3Thread instance by yourself, and thus, no beans are injected into it.

Considering you're trying to just do something in a separate thread, you can consider using @Async:

@Async
public void updateAutomationConfiguration() {
    Automation config = new Automation("user1", "success");
    automationService.updateAutomation(config);
}

Notes:

  • You have to add the @EnableAsync annotation to any configuration class (eg. your main class) to make this work.
  • Spring uses proxying by default, which means that you can't add this updateAutomationConfiguration() class to your controller itself. Direct calls to methods within the same bean bypass the proxied logic. The solution is to put this method in a separate bean which can be autowired and invoked from within the controller. I've provided more detailed answers about alternative solutions in this answer.

Spring also has a getting started guide for creating asynchronous methods.


Alternatively, there are also some ways to execute asynchronous calls within controllers, for example by using CompletableFuture within a controller:

@PutMapping("/automation/configuration")
public CompletableFuture<String> updateAutomationConfiguration() {
    return CompletableFuture.supplyAsync(() -> {
        Automation config = new Automation("user1", "success");
        return automationService.updateAutomation(config);
    });
}

Related: How to create a non-blocking @RestController webservice in Spring?

g00glen00b
  • 41,995
  • 13
  • 95
  • 133
0

Spring does not scan your runnable as it is not annotated with @Component.Try annotating it with @Component/@Service. Don't forget to set scope required scope though!

Anirudh Simha
  • 340
  • 1
  • 8
  • I tried annotating with @Component and getting org.springframework.beans.factory.BeanCreationException: while run the application – Manigandan Seetharaman May 13 '19 at 13:38
  • Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 's3Thread' defined in file [C:\Users\Manigandan.Seetharam\Documents\workspace-spring-tool-suite-4-4.2.1.RELEASE\E2E_Automation\target\classes\com\smarsh\e2e\egw\S3Thread.class]: Bean instantiation via constructor failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [com.smarsh.e2e.egw.S3Thread]: Constructor threw exception; nested exception is java.lang.NullPointerException – Manigandan Seetharaman May 13 '19 at 13:42
0

There are 2 potential solutions to your problem:

Either you need to make S3Thread class a service by annotating it with @Service or @Component and autowiring it on the calling class, or you can alternatively use the constructor for initializing your automationService, e.g. private IAutomationService automationService = new AutomationService();

Sofo Gial
  • 697
  • 1
  • 9
  • 20
0

Since your thread class is not managed by spring you will not be able to inject the spring managed beans in the S3Thread class.

In order to do that you need to create a class or factory which should be hooked into the spring life cycle.

Once you have the hold of that class you can get the appropriate bean and pass the reference onto/or used in the S3Thread class directly. Something like this

@Component
public class ApplicationContextUtils implements ApplicationContextAware {

    private static ApplicationContext ctx;

    @Override
    public void setApplicationContext(ApplicationContext appContext)
    {
        ctx = appContext;

    }

    public static ApplicationContext getApplicationContext() {
        return ctx;
    }
}
public class S3Thread implements Runnable {


@Override
public void run() { 
    Automation config = new Automation("user1","success");
 IAutomationService automationService= 
      ApplicationContextUtils.getApplicationContext().getBean(IAutomationService .class);
    automationService.updateAutomation(config);
 }
}
HarPal
  • 31
  • 4