Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

疑惑:使用Assert.notNull断言后,IDEA依然提示Method invocation 'string' may produce 'NullPointerException' #2028

Closed
ahaha-vip opened this issue Dec 20, 2021 · 13 comments
Labels

Comments

@ahaha-vip
Copy link

版本情况

JDK版本: java version "1.8.0_291"
hutool版本: 5.6.2
IntelliJ IDEA 2021.3

问题描述(包括截图)

  1. 使用了Assert.notNull断言,IDEA检测到依然可能出现空指针,使用org.springframework.util.Assert.notNull则不会有这种提示。感觉是IDEA检测不到Hutool的断言做了非空校验,但是又没有找到比较好的方式来关闭这种提示。

image
image

复现代码

    @Test
    public void okHttp() {
        OkHttpClient okHttpClient = new OkHttpClient().newBuilder().build();
        Request qryRequest = new Builder()
                .url("https://baidu.com")
                .build();

        try (Response response = okHttpClient.newCall(qryRequest).execute()) {
            // 解析响应码
            Assert.state(response.isSuccessful(), "调用接口失败");

            // 解析响应体
            ResponseBody responseBody = response.body();
            Assert.notNull(responseBody, "响应体为空");

            // 解析响应数据、
            // responseBody.string()方法IDEA提示“Method invocation 'string' may produce 'NullPointerException' ”
            String responseData = responseBody.string();
            System.out.println(responseData);
        } catch (IOException ignored) {
        }
    }
  1. 堆栈信息

  2. 测试涉及到的文件(注意脱密)

比如报错的Excel文件,有问题的图片等。

@qclucky7
Copy link

我使用过程中ObjectUtil.isEmpty()也有这种问题, 换成ObjectUtil.isNull()就没有, 不太清楚idea是怎么检测的这种

@looly
Copy link
Member

looly commented Dec 21, 2021

哎,我也奇怪,我本地也会有这个问题,IDEA不喜欢Hutool,哈哈。

@looly looly closed this as completed Dec 21, 2021
@looly looly added the question label Dec 21, 2021
@cbqqkcel
Copy link

cbqqkcel commented Apr 27, 2022

spirng 使用的是简单语句做判断,所以 idea 能静态检查

public static void isTrue(boolean expression, String message) {
if (!expression) {
throw new IllegalArgumentException(message);
}
}

hutool 不知道为啥这么简单的判断非得写个函数调用,就无法触发静态语句检查了。
public static void isTrue(boolean expression, String errorMsgTemplate, Object... params) throws IllegalArgumentException {
isTrue(expression, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
}

@ahaha-vip
Copy link
Author

spirng 使用的是简单语句做判断,所以 idea 能静态检查

public static void isTrue(boolean expression, String message) { if (!expression) { throw new IllegalArgumentException(message); } }

hutool 不知道为啥这么简单的判断非得写个函数调用,就无法触发静态语句检查了。 public static void isTrue(boolean expression, String errorMsgTemplate, Object... params) throws IllegalArgumentException { isTrue(expression, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params))); }

因为重载的方法里面支持自定义异常,这里相当于代码复用了

@cbqqkcel
Copy link

可以提供一个类似 spring 简单的方法,再说Assert就是简单的判断,如果用自定义异常就没必要使用断言来做判断了。

@ahaha-vip
Copy link
Author

加一个简单判断的重载确实可以解决这个warn,断言自定义异常可以三行变一行呀 [手动滑稽]=。=

@cbqqkcel
Copy link

不是复用的问题,应该是用了 lambda 函数调用的问题,简单函数调用都是没有问题的

下面的代码都是能正常检查出来的。

class Test {
    static void notNull(Object obj) {
        notNull0(obj);
    }

    static void notNull0(Object obj) {
        notNull1(obj);
    }

    static void notNull1(Object obj) {
        notNull2(obj);
    }

    static void notNull2(Object obj) {
        if (obj == null) {
            throw new IllegalArgumentException();
        }
    }
}

@ahaha-vip
Copy link
Author

	public static <T> T notNull(T object) throws IllegalArgumentException {
		return notNull(object, "[Assertion failed] - this argument is required; it must not be null");
	}

	public static <T> T notNull(T object, String errorMsgTemplate, Object... params) throws IllegalArgumentException {
		return notNull(object, () -> new IllegalArgumentException(StrUtil.format(errorMsgTemplate, params)));
	}

	public static <T, X extends Throwable> T notNull(T object, Supplier<X> errorSupplier) throws X {
		if (null == object) {
			throw errorSupplier.get();
		}
		return object;
	}

hutool 不知道为啥这么简单的判断非得写个函数调用,就无法触发静态语句检查了
因为重载的方法里面支持自定义异常,这里相当于代码复用了

我的意思是hutool断言的最下层有个支持自定义异常(用的函数式)的重载,因此就没有像Spring这样简单的固定抛出IllegalArgumentException,IntelliJ IDEA没有检测到的原因应该就是lambda。

	public static void notNull(@Nullable Object object, String message) {
		if (object == null) {
			throw new IllegalArgumentException(message);
		}
	}

@cbqqkcel
Copy link

嗯,是的,这个问题已经讨论清楚了。

@ahaha-vip
Copy link
Author

今天研究了下,在断言方法上增加jetbrains的注解@contract可以解决这个问题,缺点也就是有点侵入源码了

    <dependency>
        <groupId>org.jetbrains</groupId>
        <artifactId>annotations</artifactId>
        <version>23.0.0</version>
    </dependency>
    @Test
    public void testAssert() {
        Boolean obj = null;
        if (RandomUtil.randomBoolean()) {
            obj = true;
        }
        Optional<Object> optional = Optional.ofNullable(obj);

        isTrue(optional.isPresent(), RuntimeException::new);
//        cn.hutool.core.lang.Assert.isTrue(optional.isPresent(), RuntimeException::new);

        Object o = optional.get();
    }

    @org.jetbrains.annotations.Contract("true, _ -> fail")
    public static <X extends Throwable> void isFalse(boolean expression, Supplier<X> errorSupplier) throws X {
        if (expression) {
            throw errorSupplier.get();
        }
    }

    @org.jetbrains.annotations.Contract("false, _ -> fail")
    public static <X extends Throwable> void isTrue(boolean expression, Supplier<? extends X> supplier) throws X {
        if (!expression) {
            throw supplier.get();
        }
    }

https://youtrack.jetbrains.com/issue/IDEA-182726/Method-invocation-may-produce-NullPointerException-warning-while-its-checked-before

https://www.jetbrains.com/help/idea/contract-annotations.html

@ahaha-vip
Copy link
Author

不侵入代码的解决方案:https://youtrack.jetbrains.com/issue/IDEA-301217

@looly
Copy link
Member

looly commented Sep 7, 2022

@ahaha-vip 也就是需要设置IDE是吧?那就是用户端设置?

@ahaha-vip
Copy link
Author

@looly 是的,用户端在断言方法上设置Contract的表达式就行
image
image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants