0

I am writing an @TimerTrigger function in Azure Functions. To do so, I used Spring Cloud Function for Azure. The problem is I am getting a null pointer exception every time when I access the Service or JPARepository. Also the @Value("${VARIABLE}") gives null but the System.getenv("VARIABLE") does provide the value.

The code Main.Java is:

@SpringBootApplication
@EnableJpaRepositories("com.xyz.*")
@ComponentScan(basePackages = "com.xyz.*")
@EntityScan("com.xyz.*")
public class Scheduler {

    public static void main(String[] args) throws Exception {
        SpringApplication.run(Scheduler.class, args);
    }

    @Bean
    public void hello() {}
}

The Function HelloHandler.java File is:

@Component
public class HelloHandler extends AzureSpringBootRequestHandler<Void, Void> {

    @Autowired
    MyService myService;

    @Value("${VARIABLE}")
    private String variable;

    @FunctionName("hello")
    public void execute(@TimerTrigger(name = "timerInfo", schedule = "0 * * * * *") String timerInfo,
                        final ExecutionContext context){
        context.getLogger().info("Executing the function..."+variable);    // this gives null.
        context.getLogger().info(System.getenv("VARIABLE"));               // this does provide value.
        myService.hello(context);                                          // null pointer exception here.
        context.getLogger().info("Here I am...");
    }
}

Service MyService.Java is:

@Service
public class MyServiceImpl implements MyService {

    @Autowired
    private MyRepository myRepository;

    public void hello(ExecutionContext context) {
        List<User> userList = myRepository.findAll();
        for (User user : userList) {
            context.getLogger().info("USER: "+user.getId());
        }

        context.getLogger().info("Process Finished.");
    }
}

I am using below dependencies:

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-function-adapter-azure -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-function-adapter-azure</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-function-web -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-function-web</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>

It gives exception as:

Executed 'Functions.hello' (Failed, Id=90714488-b07a-41ac-ae37-d120a1a8e732, Duration=372ms)
System.Private.CoreLib: Exception while executing function: Functions.hello. System.Private.CoreLib: Result: Failure
Exception: NullPointerException: 
Stack: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.microsoft.azure.functions.worker.broker.JavaMethodInvokeInfo.invoke(JavaMethodInvokeInfo.java:22)
    at com.microsoft.azure.functions.worker.broker.JavaMethodExecutorImpl.execute(JavaMethodExecutorImpl.java:54)
    at com.microsoft.azure.functions.worker.broker.JavaFunctionBroker.invokeMethod(JavaFunctionBroker.java:57)
    at com.microsoft.azure.functions.worker.handler.InvocationRequestHandler.execute(InvocationRequestHandler.java:33)
    at com.microsoft.azure.functions.worker.handler.InvocationRequestHandler.execute(InvocationRequestHandler.java:10)
    at com.microsoft.azure.functions.worker.handler.MessageHandler.handle(MessageHandler.java:45)
    at com.microsoft.azure.functions.worker.JavaWorkerClient$StreamingMessagePeer.lambda$onNext$0(JavaWorkerClient.java:92)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: java.lang.NullPointerException
    at com.xyz.scheduler.HelloHandler.execute(HelloHandler.java:26)
    ... 16 more
.

I don't understand why it's not working with all the Spring features as expected.

mkb_mc
  • 17
  • 2
  • 10

2 Answers2

1

You have to declare a bean with the same name with your Azure function. I have my Azure functions with HttpTrigger & TimerTrigger works in the same Spring Cloud Azure function app. Try this

HelloHandler.java

public class HelloHandler extends AzureSpringBootRequestHandler<String, String> {

    @FunctionName("hello")
    public void execute(@TimerTrigger(name = "timerInfo", schedule = "0 * * * * *") String timerInfo,
                        final ExecutionContext context){
        context.getLogger().info("Executing the function..."+variable);    
        context.getLogger().info(System.getenv("VARIABLE"));               
        super.handleRequest(timerInfo, context);  // this is correct way to invoke your Spring Cloud function.
        context.getLogger().info("Here I am...");
    }
}

HelloFunction.java

@Configuration
public class HelloFunction {

    @Autowired
    private MyRepository myRepository;
    
    @Autowired
    private ExecutionContext context;
    
    @Bean
    public Function<String, String> hello() {
        return timerInfo -> {
            List<User> userList = myRepository.findAll();
            for (User user : userList) {
                context.getLogger().info("USER: "+user.getId());
            }
            context.getLogger().info("Process Finished.");
            return "";
        };
        
    }

}
Ethan Nguyen
  • 104
  • 4
  • Could you share the full code? I tried what you put here, but it's not working for me. I keep getting NullPointerException on this line: super.handleRequest(input, context). I was able to get 1 method using HttpTrigger working when I could do all of the logic in that same method. If I try to use anything Spring-like such as Autowiring or connecting to other classes it blows up with this error. – wheeleruniverse May 07 '21 at 22:59
  • Hi @jDub9 , were you able to resolve the issue ? I am also facing similar issue . Unable to autowire the service layer to the function class. – Srikant Barik Aug 20 '21 at 05:51
  • @SrikantBarik any update do you know how to fix it? – Maninder Oct 02 '22 at 19:21
  • @Maninder I don't know if it's the most ideal solution, but I did find a solution... you can look at my GitHub repository here: https://github.com/wheelerswebservices/multicloud-resume/tree/main/app. The implementation is not the best so I apologize for that. This code is multi-cloud and deploys to aws, azure, and gcp. The core package is shared by all 3. If you look in the azure folder you will see my controllers. If you look in the core folder you will see the services. The services successfully autowire ModelRepository, which is overridden in the azure dao repository. Reach out if you want. – wheeleruniverse Oct 11 '22 at 07:21
  • @SrikantBarik did you see my response above? – wheeleruniverse Oct 13 '22 at 05:39
0

Not sure why it does not work, it looks correct. I tried both @Value and System.getenv() in the demo, they worked well.

If you don't find the key(VARIABLE) in your environment variable, you will get this exception java.lang.IllegalArgumentException: Could not resolve placeholder 'XXX' in string value "${XXX}".

So it seems to get the NullPointerException in your Method hello(), try to debug the method step by step, maybe it will happen at user.getId().

enter image description here

unknown
  • 6,778
  • 1
  • 5
  • 14
  • It does work as long as it's not an Azure Function project. Once I run it as Azure Function it doesn't work. – mkb_mc Sep 14 '20 at 21:43