redis / lettuce

Advanced Java Redis client for thread-safe sync, async, and reactive usage. Supports Cluster, Sentinel, Pipelining, and codecs.
https://lettuce.io
MIT License
5.3k stars 947 forks source link

Custom command with Lettuce occurs UnsupportedOperationException #2849

Closed donggyu81 closed 1 month ago

donggyu81 commented 1 month ago

Bug Report

Current Behavior

I am trying to use the lettuce library to execute a custom command with implements ProtocolKeyword interface. However, after execution, an java.lang.UnsupportedOperationException: io.lettuce.core.output.StatusOutput does not support set(long) exception occurs.

Stack trace ```java Exception in thread "main" java.lang.UnsupportedOperationException: io.lettuce.core.output.StatusOutput does not support set(long) at io.lettuce.core.output.CommandOutput.set(CommandOutput.java:107) at io.lettuce.core.protocol.RedisStateMachine.safeSet(RedisStateMachine.java:777) at io.lettuce.core.protocol.RedisStateMachine.handleInteger(RedisStateMachine.java:428) at io.lettuce.core.protocol.RedisStateMachine$State$Type.handle(RedisStateMachine.java:206) at io.lettuce.core.protocol.RedisStateMachine.doDecode(RedisStateMachine.java:358) at io.lettuce.core.protocol.RedisStateMachine.decode(RedisStateMachine.java:319) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:840) at io.lettuce.core.protocol.CommandHandler.decode0(CommandHandler.java:791) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:765) at io.lettuce.core.protocol.CommandHandler.decode(CommandHandler.java:657) at io.lettuce.core.protocol.CommandHandler.channelRead(CommandHandler.java:597) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:1583) ```

Input Code

Input Code - implemented custom command ```java import java.nio.charset.StandardCharsets; import io.lettuce.core.protocol.ProtocolKeyword; public enum Tile38Command implements ProtocolKeyword { NEARBY, SEARCH, WITHIN, INTERSECTS; private final byte commandBytes[]; Tile38Command() { commandBytes = name().getBytes(StandardCharsets.UTF_8); } @Override public byte[] getBytes() { return commandBytes; } } ``` - main class ```java public static void main(String[] args) throws Exception { RedisURI uri = RedisURI.Builder.redis("10.177.189.59", 6397).build(); RedisClient client = RedisClient.create(uri); StatefulRedisConnection connection = client.connect(); RedisCommands sync = connection.sync(); StringCodec codec = StringCodec.UTF8; StopWatch stopWatch = new StopWatch("tile38"); stopWatch.start(); CommandArgs commandArgs = new CommandArgs<>(codec) .add("am_emd_a_a") .add("POINT") .add(35.179816) .add(129.075022); System.out.println(commandArgs.toCommandString()); String result = sync.dispatch(Tile38Command.INTERSECTS, new StatusOutput<>(codec), commandArgs); stopWatch.stop(); System.out.println(stopWatch.prettyPrint()); } ```

Expected behavior/code

10.177.189.59:6397>  intersects am_emd_a_a POINT 35.179816 129.075022
1) (integer) 0
2) 1) 1) "2647069000"
      2) "{\"type\":\"Feature\",\"geometry\":{\"type\":\"MultiPolygon\",\"coordinates\":[[[[129.073100795,35.179060681],...,[129.073100795,35.179060681]]]]},\"properties\":{\"admcode\":\"2647069000\",\"mid\":618}}"

Environment

Possible Solution

Additional context

donggyu81 commented 1 month ago

I have self solved this issue. it's my mistake. intersect returns result with Map or list. so I used NestedMultiOutput class instead of StatusOutput. ( it is matching with single value operation. ). sorry for my mistake.