Home > other >  SpelEvaluationException when initiating GET on a SftpOutboundGateway
SpelEvaluationException when initiating GET on a SftpOutboundGateway

Time:10-14

I have a Spring Integration Flow starting with a SFTPOutboundGateway. It should get a file from a SFTP server. The file contains Event objects in JSON format. My configuration is:

@Bean
public DirectChannelSpec sftpGetInputChannel() {
    return MessageChannels.direct();
}

@Bean
public QueueChannelSpec remoteFileOutputChannel() {
    return MessageChannels.queue();
}

@Bean(name = PollerMetadata.DEFAULT_POLLER)
public PollerMetadata defaultPoller() {
    PollerMetadata pollerMetadata = new PollerMetadata();
    pollerMetadata.setTrigger(new PeriodicTrigger(5000));
    return pollerMetadata;
}

@Bean
public IntegrationFlow sftpGetFlow(TransferContext context) {
    return IntegrationFlows.from("sftpGetInputChannel")
            .handle(Sftp.outboundGateway(sftpSessionFactory(context.getChannel()),
                            AbstractRemoteFileOutboundGateway.Command.GET, "payload")
                    .remoteDirectoryExpression(context.getRemoteDir())
                    .localDirectory(new File(context.getLocalDir()))
                    .localFilenameExpression(context.getLocalFilename())
                    )
            .channel("remoteFileOutputChannel")
            .transform(Transformers.fromJson(Event[].class))
            .get();
}

To get a file from the SFTP server I send a message to the gateway's input channel "sftpGetInputChannel":

boolean sent = sftpGetInputChannel.send(new GenericMessage<>(env.getRemoteDir()   "/"   env.getRemoteFilename()));

An SpelEvaluationException is thrown when trying to interprete the given filename. Both fields, remoteDir and remoteFilename are of type String:

org.springframework.messaging.MessageHandlingException: error occurred in message handler [bean 'sftpGetFlow.sftp:outbound-gateway#0' for component 'sftpGetFlow.org.springframework.integration.config.ConsumerEndpointFactoryBean#0'; defined in: 'class path resource [com/harry/potter/job/config/SftpConfiguration.class]'; from source: 'bean method sftpGetFlow']; nested exception is org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
        at org.springframework.integration.support.utils.IntegrationUtils.wrapInHandlingExceptionIfNecessary(IntegrationUtils.java:192)
        at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:79)
        at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:115)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:133)
        at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106)
        at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:570)
        at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:520)
        at com.harry.potter.job.MyTask.getFile(MyEventsTask.java:170)
        at com.harry.potter.job.myTask.runAsTask(MyEventsTask.java:112)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:566)
        at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84)
        at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
        at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:93)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
        at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
        at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:836)
Caused by: org.springframework.messaging.MessagingException: Failed to execute on session; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
        at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:448)
        at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.doGet(AbstractRemoteFileOutboundGateway.java:680)
        at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.handleRequestMessage(AbstractRemoteFileOutboundGateway.java:584)
        at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:134)
        at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:62)
        ... 21 common frames omitted
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1001E: Type conversion problem, cannot convert from org.springframework.messaging.support.GenericMessage<?> to java.lang.String
        at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:75)
        at org.springframework.expression.common.ExpressionUtils.convertTypedValue(ExpressionUtils.java:57)
        at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:377)
        at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.generateLocalFileName(AbstractRemoteFileOutboundGateway.java:1316)
        at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.get(AbstractRemoteFileOutboundGateway.java:1081)
        at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway.lambda$doGet$6(AbstractRemoteFileOutboundGateway.java:681)
        at org.springframework.integration.file.remote.gateway.AbstractRemoteFileOutboundGateway$$Lambda$30183/0x0000000000000000.doInSession(Unknown Source)
        at org.springframework.integration.file.remote.RemoteFileTemplate.execute(RemoteFileTemplate.java:439)
        ... 25 common frames omitted
Caused by: org.springframework.core.convert.ConverterNotFoundException: No converter found capable of converting from type [org.springframework.messaging.support.GenericMessage<?>] to type [java.lang.String]
        at org.springframework.core.convert.support.GenericConversionService.handleConverterNotFound(GenericConversionService.java:322)
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:195)
        at org.springframework.expression.spel.support.StandardTypeConverter.convertValue(StandardTypeConverter.java:70)
        ... 32 common frames omitted

What do I wrong?

CodePudding user response:

Okay, the problem is not within the message to get the file but in the configuration of the gateway:

.localFilenameExpression(context.getLocalFilename())

Just to set the local filename as expression is not allowed because dots - often part of the filename - is a SpEL delimiter to separate bean from method name. Hence the expression becomes invalid.

Possible expression would be:

.localFilenameExpression("#remoteFileName")

CodePudding user response:

See its JavaDocs:

/**
 * Specify a SpEL expression for local files renaming after downloading.
 * @param localFilenameExpression the SpEL expression to use.
 * @return the Spec.
 */
public S localFilenameExpression(String localFilenameExpression) {

And here is some code snippet how it works:

private String generateLocalFileName(Message<?> message, String remoteFileName) {
    if (this.localFilenameGeneratorExpression != null) {
        EvaluationContext evaluationContext = ExpressionUtils.createStandardEvaluationContext(getBeanFactory());
        evaluationContext.setVariable("remoteFileName", remoteFileName);
        return this.localFilenameGeneratorExpression.getValue(evaluationContext, message, String.class);
    }
    return remoteFileName;
}

The expression you can provide should somehow be in the context of the currently downloaded remote file. Not sure what is yours static context.getLocalFilename(). You can build a local file name based on the request message and that remoteFileName variable contexts.

See more in docs: https://docs.spring.io/spring-integration/docs/current/reference/html/sftp.html#configuring-with-the-java-dsl-3

The sample over there is like this:

.localDirectoryExpression("'myDir/'   #remoteDirectory")
.localFilenameExpression("#remoteFileName.replaceFirst('sftpSource', 'localTarget')"))
  • Related