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

Prefer NullPointerException for Null pointers #22723

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Prefer NullPointerException for Null pointers #22723

wants to merge 1 commit into from

Conversation

elharo
Copy link
Contributor

@elharo elharo commented May 12, 2024

Description

checkArgument should not be used for null checks. Use checkNotNull/requireNonNull instead.

Motivation and Context

As recommended by Effective Java

Impact

Many IllegalArgumentExceptions are now NullPointerExceptions

Test Plan

CI

Contributor checklist

  • Please make sure your submission complies with our development, formatting, commit message, and attribution guidelines.
  • PR description addresses the issue accurately and concisely. If the change is non-trivial, a GitHub Issue is referenced.
  • Documented new properties (with its default value), SQL syntax, functions, or other functionality.
  • If release notes are required, they follow the release notes guidelines.
  • Adequate tests were added if applicable.
  • CI passed.

Release Notes

== NO RELEASE NOTE ==

@elharo elharo force-pushed the nonnull branch 14 times, most recently from 187467d to 10b8e8c Compare May 12, 2024 21:36
@@ -157,7 +157,7 @@ private static Class<?> getPrimitiveType(BytecodeExpression expression, String n
{
requireNonNull(expression, name + " is null");
Class<?> leftType = expression.getType().getPrimitiveType();
checkArgument(leftType != null, name + " is not a primitive");
requireNonNull(leftType, name + " is not a primitive");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the message to use %s instead of string concat

@@ -253,7 +253,7 @@ private static Class<?> getPrimitiveType(BytecodeExpression expression, String n
{
requireNonNull(expression, name + " is null");
Class<?> leftType = expression.getType().getPrimitiveType();
checkArgument(leftType != null, name + " is not a primitive");
requireNonNull(leftType, name + " is not a primitive");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update the message to use %s instead of string concat

@@ -98,7 +98,7 @@ public CassandraPageSink(
}
for (int i = 0; i < columnNames.size(); i++) {
String columnName = columnNames.get(i);
checkArgument(columnName != null, "columnName is null at position: %d", i);
checkNotNull(columnName, "columnName is null at position: %d", i);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Preconditions recognizes only %s. Replace %d with %s.

@@ -92,7 +92,7 @@ public void assertInvalidFunction(String expr, String exceptionPattern)

public void assertQuery(@Language("SQL") String sql, Column... cols)
{
checkArgument(cols != null && cols.length > 0);
checkArgument(cols.length > 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect replacement, it will fail when cols is null

@@ -112,7 +112,7 @@ public void aggregationFunctions()
@SuppressWarnings("UnknownLanguage")
public void check(@Language("SQL") String query, Column... expectedColumns)
{
checkArgument(expectedColumns != null && expectedColumns.length > 0);
checkArgument(expectedColumns.length > 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect replacement, it will fail when expectedColumns is null

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it fails with a null pointer exception, exactly as desired

@@ -483,7 +483,7 @@ private Parser(ScalarImplementationHeader header, Method method, Optional<Constr
.collect(toImmutableSet());

SqlType returnType = method.getAnnotation(SqlType.class);
checkArgument(returnType != null, format("Method [%s] is missing @SqlType annotation", method));
requireNonNull(returnType, format("Method [%s] is missing @SqlType annotation", method));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove format

@@ -748,8 +748,8 @@ private Object invokeOperator(OperatorType operatorType, List<? extends Type> ar

private List<RowExpression> toRowExpressions(List<Object> values, List<RowExpression> unchangedValues)
{
checkArgument(values != null, "value is null");
checkArgument(unchangedValues != null, "value is null");
requireNonNull(values, "value is null");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please update the message to use the right "value" name

@@ -315,7 +315,7 @@ private void assertMergedStringStatistics(List<ColumnStatistics> statisticsList,

private static void assertMinMaxValuesWithLimit(Slice expectedMin, Slice expectedMax, List<Slice> values, int limit)
{
checkArgument(values != null && values.size() > 0);
checkArgument(values.size() > 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect replacement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is deliberate. values== null causes a NullPointerException. values <= 0 causes an IllegalArgumentException

@@ -325,7 +325,7 @@ private static void assertMinMaxValuesWithLimit(Slice expectedMin, Slice expecte

private static void assertMinMaxValuesWithLimit(Slice expectedMin, Slice expectedMax, List<Slice> values, int limit, long expectedSum)
{
checkArgument(values != null && values.size() > 0);
checkArgument(values.size() > 0);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect replacement

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is deliberate. values== null causes a NullPointerException. values <= 0 causes an IllegalArgumentException

@@ -169,7 +168,7 @@ private Subfield createNestedColumn(
Collections.reverse(elements);
String name = ((VariableReferenceExpression) currentRowExpression).getName();
ColumnHandle handle = baseColumnHandles.get(name);
checkArgument(handle != null, "Missing Column handle: " + name);
requireNonNull(handle, "Missing Column handle: " + name);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use %s for name?

@tdcmeehan
Copy link
Contributor

I don't think we want to use Guava's checkNotNull, instead we use JDK's requireNonNull.

Most of the refactoring in this PR seems to be checking that the input argument corresponds in some way to an object's internal state. e.g. that a column is a member of a table. Most don't seem to be directly validating that the input arguments are null themselves. I'm slightly more in favor of keeping the thrown exception as IllegalArgumentException, because to me it's just more clear that the problem was with the state of my input argument, not that I somehow passed in something that's null.

There's a lot of prior art to using requireNonNull to directly validate that arguments to methods and constructors are not null. I think that's a little different: here, we are moving forward a potential null pointer exception, in the hopes that we fix it sooner (ideally before merge).

@elharo
Copy link
Contributor Author

elharo commented May 13, 2024

The modernizer plugin catches the cases where Guava's checkNotNull can be replaced by Objects.requireNonNull, but it's not always a replacement. Objects.requireNonNull doesn't handle format strings and multiple argiuments whereas Guava's checkNotNull does.

@elharo
Copy link
Contributor Author

elharo commented May 13, 2024

It varies from call site to call site. In quite a few cases it's not checking an argument at all:

       ConnectorMetadata metadata = transactions.get(transactionHandle);
        checkArgument(metadata != null, "no such transaction: %s", transactionHandle);

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

Successfully merging this pull request may close these issues.

None yet

3 participants