'springboot sftp integration unsatisfied dependency expressed through filed 'gateway'

My spring-boot applications fails to start with the following exceptions:

Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'BatchConfiguration': Unsatisfied dependency expressed through field 'sftpProcessor'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'SFTPProcessor': Unsatisfied dependency expressed through field 'gateway'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com....SFTPProcessor$UploadGateway' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
...
Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'SFTPProcessor': Unsatisfied dependency expressed through field 'gateway'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com....SFTPProcessor$UploadGateway' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

And the class SFTPProcessor is a step of a spring boot batch application. It complains that the gateway cannot be Autowired. However, I don't see any obvious problem with the code below. I've searched on the internet some people talks about the messaginggateway and itemwriter are not in the same context. How can I identify the root cause and fix this issue.

import com.jcraft.jsch.ChannelSftp.LsEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.core.io.Resource;
import org.springframework.expression.common.LiteralExpression;
import org.springframework.integration.annotation.Gateway;
import org.springframework.integration.annotation.MessagingGateway;
import org.springframework.integration.annotation.ServiceActivator;
import org.springframework.integration.file.FileNameGenerator;
import org.springframework.integration.file.remote.session.CachingSessionFactory;
import org.springframework.integration.file.remote.session.SessionFactory;
import org.springframework.integration.sftp.outbound.SftpMessageHandler;
import org.springframework.integration.sftp.session.DefaultSftpSessionFactory;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;

@Component
public class SFTPProcessor {

    @Value("${sftp.host}")
    private String sftpHost;

    @Value("${sftp.port:22}")
    private int sftpPort;

    @Value("${sftp.user}")
    private String sftpUser;

    @Value("${sftp.privateKey:#{null}}")
    private Resource sftpPrivateKey;

    @Value("${sftp.privateKeyPassphrase:}")
    private String sftpPrivateKeyPassphrase;

    @Value("${sftp.password:#{null}}")
    private String sftpPasword;

    @Value("${sftp.remote.directory:/}")
    private String sftpRemoteDirectory;

    @Autowired private UploadGateway gateway;

    @Bean
    public SessionFactory<LsEntry> sftpSessionFactory() {
        DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory(true);
        factory.setHost(sftpHost);
        factory.setPort(sftpPort);
        factory.setUser(sftpUser);
        if (sftpPrivateKey != null) {
            factory.setPrivateKey(sftpPrivateKey);
            factory.setPrivateKeyPassphrase(sftpPrivateKeyPassphrase);
        } else if (sftpPasword != null) {
            factory.setPassword(sftpPasword);
        }
        factory.setAllowUnknownKeys(true);
        return new CachingSessionFactory<LsEntry>(factory);
    }

    @Bean
    @ServiceActivator(inputChannel = "toSftpChannel")
    public MessageHandler handler() {
        SftpMessageHandler handler = new SftpMessageHandler(sftpSessionFactory());
        handler.setRemoteDirectoryExpression(new LiteralExpression(sftpRemoteDirectory));
        handler.setFileNameGenerator(
                new FileNameGenerator() {
                    @Override
                    public String generateFileName(Message<?> message) {
                        if (message.getPayload() instanceof File) {
                            return ((File) message.getPayload()).getName();
                        } else {
                            throw new IllegalArgumentException("File expected as payload.");
                        }
                    }
                });
        return handler;
    }

    @MessagingGateway
    public interface UploadGateway {

        @Gateway(requestChannel = "toSftpChannel")
        void upload(File file);
    }

    public void doSFTP(String fileName) throws IOException {
        // Prepare phase
        Path tempFile = Paths.get(fileName);

        // Prerequisites
        gateway.upload(tempFile.toFile());
    }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source