Skip to content

Specify nullness for nodes in the graphql.language package #3899

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

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

Conversation

mk868
Copy link
Contributor

@mk868 mk868 commented Apr 6, 2025

Related: #3878

I applied @NullMarked and @Nullable annotations to these classes:

  • graphql.language.Node - partially annotated with @Nullable
  • graphql.language.AbstractNode
  • graphql.language.ArrayValue
  • graphql.language.BooleanValue
  • graphql.language.EnumValue
  • graphql.language.FloatValue
  • graphql.language.IntValue
  • graphql.language.NullValue
  • graphql.language.ObjectValue
  • graphql.language.ScalarValue
  • graphql.language.StringValue - I was not sure about the nullability of value, for now I marked it @Nullable.
  • graphql.language.Value
  • graphql.language.VariableReference

Notes

  • SourceLocation sourceLocation - can contain a null value in all places

Potential problems (will be pointed by #3852 )

  • EnumValue.Builder#build() can build an EnumValue object with a null name
  • FloatValue.Builder#build() can build an FloatValue object with a null value
  • IntValue.Builder#build() can build an IntValue object with a null value
  • VariableReference.Builder#build() can build an VariableReference object with a null name

Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR applies nullability annotations across the graphql.language package to clarify which fields and parameters can be null.

  • Added @NullMarked and @nullable annotations to key classes and constructors.
  • Updated Builder classes for several Value types to accept null parameters.
  • Adjusted method signatures (e.g. isEqualTo) and field declarations to reflect nullability.

Reviewed Changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
VariableReference.java Annotated the class and its Builder with nullability hints.
Value.java Marked the interface with @NullMarked.
StringValue.java Adjusted the field and getter for value to be @nullable.
ScalarValue.java Applied @NullMarked to the interface.
ObjectValue.java Annotated constructors and Builder methods with @nullable.
NullValue.java Updated constructor and Builder to support null SourceLocation.
Node.java Updated getSourceLocation and isEqualTo for nullability.
IntValue.java, FloatValue.java, EnumValue.java, BooleanValue.java, ArrayValue.java, AbstractNode.java Applied similar nullability annotations to constructors, methods, and Builder classes.

private ImmutableList<Comment> comments = emptyList();
private String name;
private @Nullable String name;
Copy link
Preview

Copilot AI May 11, 2025

Choose a reason for hiding this comment

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

The VariableReference.Builder now allows a null name. Consider adding validation in the build() method to ensure that a non-null name is provided if that is an invariant in your domain.

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

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

name in the above constructor and builder method are not nullable, did you meant to make this field nullable?

I think in practice, a VariableReference should always have a non-nullable name

private SourceLocation sourceLocation;
private String name;
private @Nullable SourceLocation sourceLocation;
private @Nullable String name;
Copy link
Preview

Copilot AI May 11, 2025

Choose a reason for hiding this comment

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

The EnumValue.Builder permits a null name. It may be beneficial to enforce a non-null name during object construction if that is required by the API contract.

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

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

Hello, thanks for your patience while away for Easter.

In this builder, name is set to nullable, but the constructor above has name as non-nullable, and the builder method below has it as non-nullable. Did you mean for the Builder's name to be instead non-nullable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, nullable fields in the builder are expected.
By default, when a builder instance is created, all values are set to their defaults (null for reference fields) - thus, it's necessary to mark these fields @Nullable.
This initial Builder state represents an incomplete configuration, and the EnumValue should not be constructible in this state - calling the build() method should result in an IllegalStateException.

I planned to add something like this later:

public EnumValue build() {
    if (name == null) {
        throw new IllegalStateException("name must be set");
    }
    return new EnumValue(name, sourceLocation, comments, ignoredChars, additionalData);
}

private SourceLocation sourceLocation;
private BigInteger value;
private @Nullable SourceLocation sourceLocation;
private @Nullable BigInteger value;
Copy link
Preview

Copilot AI May 11, 2025

Choose a reason for hiding this comment

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

The IntValue.Builder now accepts a null value. Consider adding a check in the build() method to prevent creating an IntValue instance with a null value if that contradicts expected behavior.

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

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

Same comment as for FloatValue, I will double check if a null value is in practice possible or not

private SourceLocation sourceLocation;
private BigDecimal value;
private @Nullable SourceLocation sourceLocation;
private @Nullable BigDecimal value;
Copy link
Preview

Copilot AI May 11, 2025

Choose a reason for hiding this comment

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

The FloatValue.Builder now permits a null value. If a non-null value is expected, it would be prudent to validate this in the build() method to prevent possible misuse, as noted in the PR description.

Copilot uses AI. Check for mistakes.

Copy link
Member

Choose a reason for hiding this comment

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

This builder should be consistent with the constructor for value

@andimarek @bbakerman: is it possible in practice for FloatValue to ever be constructed with a null? Or would such an object always be constructed as a NullValue?

@dondonz
Copy link
Member

dondonz commented May 11, 2025

Giving Copilot a try for fun, I'm curious what it says

private SourceLocation sourceLocation;
private String value;
private @Nullable SourceLocation sourceLocation;
private @Nullable String value;
Copy link
Member

Choose a reason for hiding this comment

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

Similar to above Value classes, I will double check if value can be nullable or if in practice it is represented by a NullValue

@dondonz
Copy link
Member

dondonz commented Jun 12, 2025

Coming back in here to say thanks for waiting and thanks for the PR. We have a new PR up to add ErrorProne & NullAway checks which I'd like to merge in before new JSpecify PRs

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.

2 participants