Skip to content

Conversation

@cpovirk
Copy link
Collaborator

@cpovirk cpovirk commented Sep 26, 2025

Most of these came to my attention during the testing of
RedundantNullCheck.

Notes:

  • For BufferedInputStream and FilterInputStream, see
    FilterInputStream and BufferedInputStream protected fields should likely be @Nullable #128.
  • For URL, the docs for getAuthority() don't mention null, but
    it's easy enough to demonstrate that null is a possible return
    value:
    var u = new URL("mailto:foo@bar.com");
    System.out.println("authority " + u.getAuthority());
  • AlgorithmParameters.toString() is gross but documented as such, as
    eamonnmcmanus points out.
  • Matcher.group() is unfortunate: At one point, it could not return
    null, but that changed, as documented since
    JDK-8274663. The change
    is a consequence of
    usePattern,
    which was added all the way back in Java 5. I am a little tempted to
    lie here and leave the type as non-null.
  • In Component, I also removed an annotation on the package-private
    helper method used by getName().
  • In ResultSet, getBlob and getObject have no documentatino about
    null returns. Gemini wrote me some code that demonstrates the
    possible null returns
    .
  • Also in ResultSet, I simplified some type-parameter declarations.
    This ensures that the Class<T> parameter has its type argument in
    bounds, and it makes no difference to the result type, which is always
    nullable, regardless of the type argument.

Fixes #128

Most of these came to my attention during the testing of
[RedundantNullCheck](google/error-prone#5121).

Notes:

- For `BufferedInputStream` and `FilterInputStream`, see
  #128.
- For `URL`, the docs for `getAuthority()` don't mention `null`, but
  it's easy enough to demonstrate that `null` is a possible return
  value:
  ```java
  var u = new URL("mailto:foo@bar.com");
  System.out.println("authority " + u.getAuthority());
  ```
- `AlgorithmParameters.toString()` is gross but documented as such, as
  eamonnmcmanus points out.
- `Matcher.group()` is unfortunate: At one point, it could not return
  `null`, but that changed, as documented since
  [JDK-8274663](https://bugs.openjdk.org/browse/JDK-8274663). The change
  is a consequence of
  [`usePattern`](https://docs.oracle.com/en/java/javase/25/docs/api/java.base/java/util/regex/Matcher.html#usePattern(java.util.regex.Pattern)),
  which was added all the way back in Java 5. I am a little tempted to
  lie here and leave the type as non-null.
- In `Component`, I also removed an annotation on the package-private
  helper method used by `getName()`.
- In `ResultSet`, `getBlob` and `getObject` have no documentatino about
  `null` returns. Gemini [wrote me some code that demonstrates the
  possible null returns](https://g.co/gemini/share/776a7669ae47).
- Also in `ResultSet`, I simplified some type-parameter declarations.
  This ensures that the `Class<T>` parameter has its type argument in
  bounds, and it makes no difference to the result type, which is always
  nullable, regardless of the type argument.

Fixes #128
* @since 1.1
*/
public String getName() {
public @Nullable String getName() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I could see also adding @Nullable on the parameter of setName, but I didn't give it much thought.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Would seem consistent to make the setName parameter @Nullable - the check for nameExplicitlySet helps to account for that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh, thanks, I hadn't paid attention to the nameExplicitlySet check. That does suggest that upstream is at minimum resigned to supporting null :) Done.

Copy link
Collaborator

@wmdietl wmdietl left a comment

Choose a reason for hiding this comment

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

Looks good. If you want, make setName consistent.

* if this parameter object has not been initialized.
*/
public final String toString() {
public final @Nullable String toString() {
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 really ugly, as you note. It breaks behavioral subtyping, contradicting the contract from java.lang.Object#toString.
jspecify/jspecify#111 would say that this annotation should cause a distinct warning.
But as this is what the code is clearly doing, the annotation matches the code.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep :(

One note for anyone in the future who might be interested: It's not really fair of me to call this annotation "missing" in the way that the others are: This class is not @NullMarked, so JSpecify would say that the return type is unspecified. (Of course, I could hardly criticize a tool for still treating it as non-null, given everything you've said about toString().) Thus, the @Nullable annotation here is "missing" only in the sense that all unannotated code is "missing" tons of annotations. That is in contrast to the other edits I'm making, which are in null-marked classes, since those are changing types from non-null to nullable.

* @since 1.1
*/
public String getName() {
public @Nullable String getName() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would seem consistent to make the setName parameter @Nullable - the check for nameExplicitlySet helps to account for that.

Copy link
Collaborator Author

@cpovirk cpovirk left a comment

Choose a reason for hiding this comment

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

Thanks.

I have a sinking feeling that I'll have some work to do before I can import this one into Google. I may end up locally undoing the Matcher.group change on the grounds that it's more valuable to land the rest than to be strictly correct there.

* @since 1.1
*/
public String getName() {
public @Nullable String getName() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Oh, thanks, I hadn't paid attention to the nameExplicitlySet check. That does suggest that upstream is at minimum resigned to supporting null :) Done.

* if this parameter object has not been initialized.
*/
public final String toString() {
public final @Nullable String toString() {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep :(

One note for anyone in the future who might be interested: It's not really fair of me to call this annotation "missing" in the way that the others are: This class is not @NullMarked, so JSpecify would say that the return type is unspecified. (Of course, I could hardly criticize a tool for still treating it as non-null, given everything you've said about toString().) Thus, the @Nullable annotation here is "missing" only in the sense that all unannotated code is "missing" tons of annotations. That is in contrast to the other edits I'm making, which are in null-marked classes, since those are changing types from non-null to nullable.

@cpovirk cpovirk merged commit 91f7b36 into main Sep 29, 2025
21 checks passed
@cpovirk cpovirk deleted the sep2025 branch September 29, 2025 18:10
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.

FilterInputStream and BufferedInputStream protected fields should likely be @Nullable

3 participants