open-dingtalk / dingtalk-stream-sdk-java

Java SDK for DingTalk Stream Mode API, Compared with the webhook mode, it is easier to access the DingTalk platform
MIT License
9 stars 5 forks source link

在JDK21情况下,注册lambda声明的OpenDingTalkCallbackListener,发生异常:illegal callback implementation #8

Closed tonnyp closed 8 months ago

tonnyp commented 9 months ago

问题现象:

在JDK21版本下,使用lambda方式声明了OpenDingTalkCallbackListener,并在registerCallbackListener的使用的场景,会抛异常com.dingtalk.open.app.api.OpenDingTalkAppException: illegal callback implementation 在JDK8~20版本,不会出现问题。

根因

com.dingtalk.open.app.api.callback.CallbackDescriptor#build 逻辑中调用com.dingtalk.open.app.api.common.LambdaUtils#isLambda判断了callback是否是lambda com.dingtalk.open.app.api.common.LambdaUtils#isLambda 的判断Lambda方法是获取callback的className,判断是否符合正则 .*\$\$Lambda\$[0-9]+/.*

在JDK8~20下,返回的是JdkCheck$$Lambda$14/0x0000007001000a10,正则可以匹配到 但是JDK21变更了className的值,返回内容为JdkCheck$$Lambda/0x0000008801002a00,正则匹配不到

修复

  1. 增加JDK判断Util,参考代码

`

public class JavaVersionUtil {
    private static final String JAVA_VERSION = System.getProperty("java.version");

    public static String getJavaVersion() {
        return JAVA_VERSION;
    }

    public static boolean isJavaVersion(int majorVersion) {
        return getMajorJavaVersion() == majorVersion;
    }

    private static int getMajorJavaVersion() {
        String[] versionSplit = JAVA_VERSION.split("\\.");
        if (versionSplit[0].equals("1")) {
            // Java 6, 7, 8
            return Integer.parseInt(versionSplit[1]);
        } else {
            // Java 9 or higher
            return Integer.parseInt(versionSplit[0]);
        }
    }
}

`

  1. 修改LambdaUtils `

    private static final Pattern LAMBDA_PATTERN_JDK_21 = Pattern.compile(".*\\$\\$Lambda/.*");
    
    private static final Pattern LAMBDA_PATTERN_BEFORE_JDK_21 = Pattern.compile(".*\\$\\$Lambda\\$[0-9]+/.*");
    
    private static final Pattern PARAMETER_TYPE_PATTERN = Pattern.compile("\\((.*)\\).*");
    
    private static final String WRITE_REPLACE = "writeReplace";
    
    public static boolean isLambda(Object obj) {
        if (obj == null) {
            return false;
        }
    
        if (obj.getClass().isSynthetic()) {
            if (isJavaVersion(21)){
                if (LAMBDA_PATTERN_JDK_21.matcher(obj.getClass().getName()).matches()) {
                    return true;
                }
            }else {
                if (LAMBDA_PATTERN_BEFORE_JDK_21.matcher(obj.getClass().getName()).matches()) {
                    return true;
                }
            }
        }
        return false;
    }

`

1.8之后各个版本的lambda对象obj.getClass().getSimpleName()结果

`

JAVA_VERSION:   
1.8.0_292
getMajorJavaVersion:    
8
runnableLambdaClassName:    
JdkCheck$$Lambda$1/2003749087

JAVA_VERSION:   
11.0.18
getMajorJavaVersion:    
11
runnableLambdaClassName:    
JdkCheck$$Lambda$14/0x0000000800067040

JAVA_VERSION:   
17.0.10
getMajorJavaVersion:    
17
runnableLambdaClassName:    
JdkCheck$$Lambda$14/0x0000007001000a10

JAVA_VERSION:   
18.0.2.1
JAVA_RUNTIME_VERSION:   
18.0.2.1+1
getMajorJavaVersion:    
18
runnableLambdaClassName:    
JdkCheck$$Lambda$14/0x0000000800c029f0

JAVA_VERSION:   
19.0.2
JAVA_RUNTIME_VERSION:   
19.0.2+7
getMajorJavaVersion:    
19
runnableLambdaClassName:    
JdkCheck$$Lambda$14/0x00000008010029f0

JAVA_VERSION:   
20.0.2
JAVA_RUNTIME_VERSION:   
20.0.2+9
getMajorJavaVersion:    
20
runnableLambdaClassName:    
JdkCheck$$Lambda$14/0x00000070010029f8

JAVA_VERSION:   
21.0.2
JAVA_RUNTIME_VERSION:   
21.0.2+13-LTS
getMajorJavaVersion:    
21
runnableLambdaClassName:    
JdkCheck$$Lambda/0x0000007001002a08

JAVA_VERSION:   
21.0.2
JAVA_RUNTIME_VERSION:   
21.0.2+13-LTS-jvmci-23.1-b30
getMajorJavaVersion:    
21
runnableLambdaClassName:    
JdkCheck$$Lambda/0x0000008801002a00

`

qwangseu commented 8 months ago

感谢反馈,近期会跟进完善

qwangseu commented 8 months ago

1.3.1版本已修复