2

After upgrading Spring Boot from 2.7 to 3.4, receiving message from TCP server to our service is getting changed with different code. For example, previously the received message is 1784 after deserialization of that message, and now it has changed to 1684, which is a response message that we need to send back to the server.

Below is the error we are currently facing:

    ERROR [Regi-service,,,,,,,] 8 --- [pool-2-thread-3] [                                                 ] a.s.o.d.m.r.DeserializedIsoMessage       : Extracted raw message type value: 6292 (int), hex: 1894
2025-10-31T09:02:41.411+01:00 ERROR [otis-service,,,,,,,] 8 --- [pool-2-thread-3] [                                                 ] at.regi.otis.api.oli.OliController        : Deserialization failed

java.util.NoSuchElementException: No value present
    at java.base/java.util.Optional.orElseThrow(Optional.java:377) ~[na:na]
    at at.regi.otis.domain.message.request.RequestMessageType.byType(RequestMessageType.java:549) ~[!/:3.0.0]
    at at.regi.otis.domain.message.request.DeserializedIsoMessage.type(DeserializedIsoMessage.java:36) ~[!/:3.0.0]
    at at.regi.otis.domain.message.request.DeserializedRequestMessageWithType.type(DeserializedRequestMessageWithType.java:15) ~[!/:3.0.0]
    at at.regi.otis.domain.message.request.RequestMessage.type(RequestMessage.java:41) ~[!/:3.0.0]
    at at.regi.otis.api.oli.OliController.handle(OliController.java:60) ~[!/:3.0.0]
    at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:169) ~[spring-messaging-6.2.2.jar!/:6.2.2]
    at org.springframework.integration.handler.support.IntegrationInvocableHandlerMethod.doInvoke(IntegrationInvocableHandlerMethod.java:45) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:119) ~[spring-messaging-6.2.2.jar!/:6.2.2]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper$HandlerMethod.invoke(MessagingMethodInvokerHelper.java:1086) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.invokeHandlerMethod(MessagingMethodInvokerHelper.java:569) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.processInternal(MessagingMethodInvokerHelper.java:482) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.support.MessagingMethodInvokerHelper.process(MessagingMethodInvokerHelper.java:360) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:114) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:95) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:145) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.AbstractMessageHandler.doHandleMessage(AbstractMessageHandler.java:105) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.AbstractMessageHandler.handleWithMetrics(AbstractMessageHandler.java:90) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:70) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:145) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:106) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:72) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.channel.AbstractMessageChannel.sendInternal(AbstractMessageChannel.java:378) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.channel.AbstractMessageChannel.sendWithMetrics(AbstractMessageChannel.java:349) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:329) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSend(GenericMessagingTemplate.java:187) ~[spring-messaging-6.2.2.jar!/:6.2.2]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:234) ~[spring-messaging-6.2.2.jar!/:6.2.2]
    at org.springframework.messaging.core.GenericMessagingTemplate.doSendAndReceive(GenericMessagingTemplate.java:47) ~[spring-messaging-6.2.2.jar!/:6.2.2]
    at org.springframework.messaging.core.AbstractMessagingTemplate.sendAndReceive(AbstractMessagingTemplate.java:46) ~[spring-messaging-6.2.2.jar!/:6.2.2]
    at org.springframework.integration.core.MessagingTemplate.sendAndReceive(MessagingTemplate.java:107) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.gateway.MessagingGatewaySupport.doSendAndReceive(MessagingGatewaySupport.java:687) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveWithMetrics(MessagingGatewaySupport.java:675) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceive(MessagingGatewaySupport.java:612) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.gateway.MessagingGatewaySupport.sendAndReceiveMessage(MessagingGatewaySupport.java:588) ~[spring-integration-core-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.ip.tcp.TcpInboundGateway.doOnMessage(TcpInboundGateway.java:125) ~[spring-integration-ip-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.ip.tcp.TcpInboundGateway.onMessage(TcpInboundGateway.java:103) ~[spring-integration-ip-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.ip.tcp.connection.TcpNetConnection.receiveAndProcessMessage(TcpNetConnection.java:233) ~[spring-integration-ip-6.2.4.jar!/:6.2.4]
    at org.springframework.integration.ip.tcp.connection.TcpNetConnection.run(TcpNetConnection.java:206) ~[spring-integration-ip-6.2.4.jar!/:6.2.4]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
    at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]

2025-10-31T09:02:41.412+01:00 INFO  [Regi-service,,,,,,,] 8 --- [pool-2-thread-3] [                                                 ] at.regi.otis.api.oli.OliController        : Started errorResponse method

Some received request messages are working correctly, but in between some are failing with the above error.

This is the deserialize code:

@Override
public RequestMessageType type() {
    int rawType = deserializedMessage().getType();
    String formattedType = String.format("%02x", rawType);
    log.error("Extracted raw message type value: {} (int), hex: {}", rawType, formattedType);
    return RequestMessageType.byType(formattedType);
}

we are using spring-intergation-ip-6.4.2.jar it has ByteArrayRawSerializer class like this

public abstract class AbstractByteArraySerializer implements Serializer<byte[]>, Deserializer<byte[]>, ApplicationEventPublisherAware {
    public static final int DEFAULT_MAX_MESSAGE_SIZE = 2048;
    protected final LogAccessor logger = new LogAccessor(this.getClass());
    private int maxMessageSize = 2048;
    private ApplicationEventPublisher applicationEventPublisher;

    public AbstractByteArraySerializer() {
    }

    public int getMaxMessageSize() {
        return this.maxMessageSize;
    }

    public void setMaxMessageSize(int maxMessageSize) {
        this.maxMessageSize = maxMessageSize;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }

    protected void checkClosure(int bite) throws IOException {
        if (bite < 0) {
            this.logger.debug("Socket closed during message assembly");
            throw new IOException("Socket closed during message assembly");
        }
    }

    protected void publishEvent(Exception cause, byte[] buffer, int offset) {
        TcpDeserializationExceptionEvent event = new TcpDeserializationExceptionEvent(this, cause, buffer, offset);
        if (this.applicationEventPublisher != null) {
            this.applicationEventPublisher.publishEvent(event);
        } else {
            this.logger.trace(() -> {
                return "No event publisher for " + event;
            });
        }

    }
}

RequestMessageType

    public static RequestMessageType byType(String type) {
            Optional<RequestMessageType> match = Arrays.stream(RequestMessageType.values())
                    .filter(message -> message.type.equals(type))
                    .findFirst();
    
            if (match.isEmpty()) {
                log.error("RequestMessageType lookup FAILED for type string: '{}'. No matching enum found.", type);
            }
    
            return match.orElseThrow();
        }
9
  • The problem isn't in the block of code you've posted. As the stack trace says, the exception is thrown because somewhere you've tried to get a value from an empty Optional with orElseThrow. I'd suggest looking at the RequestMessageType class first for somewhere you're using orElseThrow, as that's the first class in the stack. Commented Oct 30 at 14:21
  • Hello. @SiripiReddy Giri, I have tried you below solution by using that code in my socket configuration and for you info serializer.setByteOrder this method was not avaliable in spring integration till 6.5.2 i have checked this so, instead i created that method in ISO file and used but still the issue persists with same error in below comments Commented Oct 31 at 8:25
  • I have given the full stack trace above even after trying with below solution. @DrRelling Commented Oct 31 at 8:28
  • And for you information yours is always BIG_ENDIAN so i don't think byte order will cause a issue Commented Oct 31 at 14:06
  • So the problem is that formattedType is null? Commented Nov 5 at 13:00

1 Answer 1

4

I found the root cause of this issue. The problem was not in the business logic but how Spring Integration (Spring Framework 6) handles byte based message serialization internally.

The problem was fixed for all message types when we specifically set the byte order in our custom deserializer.

@Bean
public ByteArrayRawSerializer customDeserializer() {
    ByteArrayRawSerializer serializer = new ByteArrayRawSerializer();
    serializer.setByteOrder(ByteOrder.LITTLE_ENDIAN);// this one depends on server
    return serializer;
}

Then we can use the above code in TCP connection Factory.

@Bean
public TcpNetServerConnectionFactory serverConnectionFactory() {
    TcpNetServerConnectionFactory factory = new TcpNetServerConnectionFactory(12345);
    factory.setDeserializer(customDeserializer());
    factory.setSerializer(customDeserializer());
    return factory;
}

I think after Spring Boot 3.4, the byte order used in TCP serialization was changed and it will show message type parsing.
I think this will work.

Sign up to request clarification or add additional context in comments.

2 Comments

I think the blame for Spring is not fully correct. The out-of-the-box ByteArrayRawSerializer just does this: outputStream.write(bytes);. The ByteOrder has nothing to do over there. Please, elaborate where exactly in the Spring Integration we can incorporate that ByteOrder to make the fix in the library for everyone. Otherwise, explain, please, your custom ByteArrayRawSerializer.
[deleted]
[deleted]
I'm sorry. I don't setByteOrder() in the ByteArrayRawSerializer hierarchy even in v6.4.2 tag: github.com/spring-projects/spring-integration/blob/v6.4.2/…. Please, elaborate.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.