teuber789
teuber789

Reputation: 1637

Invocation of Spring Cloud AWS Messaging package causes dependent beans to be null

I have a Spring Boot project that I'm using to receive events from an Amazon SQS queue. I've been using the Spring Cloud AWS project to make this easier.

The problem is this: the Spring Boot application starts up just fine, and appears to instantiate all the necessary beans just fine. However, when the method that is annotated with SqsListener is invoked, all the event handler's dependent beans are null.

Another thing that's important to note: I have two methods of propagating the event: 1) thru a POST web service call, and 2) thru the Amazon SQS. If I choose to run the event as a POST call with the same data in the POST body, it works just fine. The injected dependencies are only ever null whenever the SQSListener method is invoked by the SimpleMessageListenerContainer.

Classes:

@Service("systemEventsHandler")
public class SystemEventsHandler {

    // A service that this handler depends on
    private CustomService customService;
    private ObjectMapper objectMapper;

    @Autowired
    public SystemEventsHandler(CustomService customService, ObjectMapper objectMapper) {
        this.matchStatusSvc = matchStatusSvc;
        this.objectMapper = objectMapper;
    }

    public void handleEventFromHttpCall(CustomEventObject event) {
        // Whenever this method is called, the customService is 
        // present and the method call completes just fine.
        Assert.notNull(objectMapper, "The objectMapper that was injected was null");
        customService.handleEvent(event);
    }

    @SqsListener(value = "sqsName", deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
    private void handleEventFromSQSQueue(@NotificationMessage String body) throws IOException {
        // Whenever this method is called, both the objectMapper and 
        // the customService are null, causing the invocation to 
        // fail with a NullPointerException
        CustomEventObject event = objectMapper.readValue(body, CustomEventObject.class);
        matchStatusSvc.scoresheetUploaded(matchId);
    }
}

The controller (for when I choose to run the event as a POST). As stated above, it works just fine whenever I run it as a POST call.

@RestController
@RequestMapping("/events")
public class SystemEventsController {

    private final SystemEventsHandler sysEventSvc;

    @Autowired
    public SystemEventsController(SystemEventsHandler sysEventSvc) {
        this.sysEventSvc = sysEventSvc;
    }

    @RequestMapping(value = "", method = RequestMethod.POST)
    public void handleCustomEvent(@RequestBody CustomEventObject event) {
        sysEventSvc.handleEventFromHttpCall(event);
    }
}

Pertinent config:

@Configuration
public class AWSSQSConfig {

    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(AmazonSQSAsync amazonSQS) {
        SimpleMessageListenerContainer msgListenerContainer = simpleMessageListenerContainerFactory(amazonSQS).createSimpleMessageListenerContainer();
        msgListenerContainer.setMessageHandler(queueMessageHandler(amazonSQS));

        return msgListenerContainer;
    }

    @Bean
    public SimpleMessageListenerContainerFactory simpleMessageListenerContainerFactory(AmazonSQSAsync amazonSQS) {
        SimpleMessageListenerContainerFactory msgListenerContainerFactory = new SimpleMessageListenerContainerFactory();
        msgListenerContainerFactory.setAmazonSqs(amazonSQS);
        msgListenerContainerFactory.setMaxNumberOfMessages(10);
        msgListenerContainerFactory.setWaitTimeOut(1);
        return msgListenerContainerFactory;
    }

    @Bean
    public QueueMessageHandler queueMessageHandler(AmazonSQSAsync amazonSQS) {
        QueueMessageHandlerFactory queueMsgHandlerFactory = new QueueMessageHandlerFactory();
        queueMsgHandlerFactory.setAmazonSqs(amazonSQS);
        QueueMessageHandler queueMessageHandler = queueMsgHandlerFactory.createQueueMessageHandler();
        return queueMessageHandler;
    }

    @Bean(name = "amazonSQS", destroyMethod = "shutdown")
    public AmazonSQSAsync amazonSQSClient() {
        AmazonSQSAsyncClient awsSQSAsyncClient = new AmazonSQSAsyncClient(new DefaultAWSCredentialsProviderChain());
        return awsSQSAsyncClient;
    }
}

Other info:

Any thoughts?

Upvotes: 0

Views: 729

Answers (1)

teuber789
teuber789

Reputation: 1637

As spencergibb suggested in his comment above, changing the method's visibility from private to public worked.

Upvotes: 0

Related Questions