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

Add a null-check to java enum safeValueOf #5904

Merged
merged 12 commits into from
May 28, 2024

Conversation

BoD
Copy link
Contributor

@BoD BoD commented May 17, 2024

Fix for #5901

  • Also make the constructor of the class and of UNKNOWN__ nullable
  • Also call super() in equals() and hashCode()

@BoD BoD requested a review from martinbonnin as a code owner May 17, 2024 14:25
Copy link

netlify bot commented May 17, 2024

Deploy Preview for apollo-android-docs canceled.

Name Link
🔨 Latest commit 7a3c146
🔍 Latest deploy log https://app.netlify.com/sites/apollo-android-docs/deploys/6655ef0ff619ec0008bf35c5

Copy link
Contributor

@martinbonnin martinbonnin left a comment

Choose a reason for hiding this comment

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

A few comments. Also, can we do the same for Kotlin codegen?

Comment on lines 63 to 64
return true;
return super.equals(o);
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the rationale for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I noticed that without this, 2 unknown enums with a different rawValue would still be equal, since that field is not included in the comparison. The super version does include the field in the comparison.

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't it compare rawValues instead? I would expect Object.equals() to do referential equality only?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're totally right! I assumed equals was implemented in the base class but it's not, so calling super doesn't work. In the Kotlin version the equals/hashCode is ad-hoc, I'll do the same in Java.

}
return false;
}

@Override
public int hashCode() {
if (!$hashCodeMemoized) {
int __h = 1;
int __h = super.hashCode();
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here. Do we really need that change?

@@ -86,7 +86,7 @@ internal class EnumAsClassBuilder(
.returns(selfClassName)
.addCode(
CodeBlock.builder()
.beginControlFlow("switch($rawValue)")
.beginControlFlow("switch ($T.requireNonNull($rawValue))", JavaClassNames.Objects)
Copy link
Contributor

Choose a reason for hiding this comment

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

TIL about Objects.requireNonNull. Should we use that instead of

public static <T> T checkNotNull(T value, String errorMessage) {
?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was almost sure we had something like that but couldn't find it anymore 😅. Ours is a bit nicer since you can pass a message - so I'd keep it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment on ours?

// A version of Objects.requireNonNull that allows a customized message

@BoD
Copy link
Contributor Author

BoD commented May 17, 2024

can we do the same for Kotlin codegen?

You're right! We can make the class constructor private. I'd keep the Kotlin UNKNOWN__ constructor public though as it's a nice way to signal a warning when using it, thanks to the opt-in annotation. On the other hand, it's still possible to call safeValueOf without any warning... Maybe safeValueOf should be annotated too?

@martinbonnin
Copy link
Contributor

I'd keep the Kotlin UNKNOWN__ constructor public though as it's a nice way to signal a warning when using it, thanks to the opt-in annotation

I'd try to keep the symmetry with Java as much as possible.

On the other hand, it's still possible to call safeValueOf without any warning... Maybe safeValueOf should be annotated too?

I'd go for that. And rename the @ApolloEnumConstructor to @ApolloUnknownEnum or something like that.

@BoD
Copy link
Contributor Author

BoD commented May 20, 2024

Turns out, actually in Kotlin we can't make the UNKOWN__ constructor private, because unlike Java, outer classes can't access private constructors of inner classes. I kept the optin annotation there, and also applied it to safeValueOf.

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

2 participants