-
Notifications
You must be signed in to change notification settings - Fork 37
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
[Nullability Annotations to Java Classes] Add Missing Nullability Annotations to Comment
Network Client Classes (safe
)
#2868
[Nullability Annotations to Java Classes] Add Missing Nullability Annotations to Comment
Network Client Classes (safe
)
#2868
Conversation
Warning: "'switch' statement on enum type 'org.wordpress.android.fluxc.model.CommentStatus' misses case 'UNREPLIED'"
Warning: "Variable is already assigned to this value"
FYI: 'nn-a' stands for 'non-null annotation'.
8219631
to
645d3a5
Compare
Comment
Client Classes (safe
)Comment
Network Client Classes (safe
)
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'. ------------------------------------------------------------------------ You will notice that I added extra conditions for when to trigger 'createNewComment(...)' versus 'createNewReply(...)' versus just throwing an illegal state exception for any other condition. if (payload.post != null && payload.reply == null) { ... } else if (payload.reply != null && payload.post == null) { ... } else { throw IllegalStateException(...) } I did that because the two 'RemoteCreateCommentPayload' constructors are also defined as such and thus the callers should also respect their contract in order to avoid any NPE or an illegal app state. I also chose to keep the 'payload.reply == null' condition and add the extra 'payload.post == null' condition because the 'payload.reply == null' condition was already present.
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'nl-a' stands for 'nullable annotation'.
Warning: "Explicit type argument CommentModel can be replaced with <>"
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
Warning: "'if' statement can be replaced with 'switch' statement"
FYI: 'n-a' stands for 'nullability annotations'.
FYI: 'n-a' stands for 'nullability annotations'.
Both those payload constructors are actually meant to and used by client apps (ie. JP/WPAndroid). They just seem unused as they are not being directly used via the example app or any unit/ui tests within this repo.
Warning: "Raw use of parameterized class 'Action'"
The 'instantiateCommentModel(...)' related 'CommentStore' methods is being in production and are only being used on a couple of connected tests. Thus, it is better to remove those and not have them exposed and available for clients like JP/WPAndroid to exploit. PS: This change was done to assist with a future refactor and in order to avoid extra testing.
Warning: "Condition 'payload.likes != null' is always 'true'"
Warning: "Explicit type argument LikeModel can be replaced with <>"
Warnings: - "Test class name 'ReleaseStack_CommentTestWPCom' doesn't match regex '[A-Z][A-Za-z\d]*Test(s|Case)?|Test[A-Z][A-Za-z\d]*|IT(.*)|(.*) IT(Case)?'" - "Test class name 'ReleaseStack_CommentTestXMLRPCCom' doesn't match regex '[A-Z][A-Za-z\d]*Test(s|Case)?|Test[A-Z][A-Za-z\d]*|IT(.*)|(.*) IT(Case)?'"
Warnings: "Exception 'java.lang.InterruptedException' is never thrown in the method"
Warning: "'assertEquals()' can be simplified to 'assertNull()'"
Warning: "'application' is deprecated" Explanation: Accessing this field directly is inherently incompatible with 'org.robolectric.annotation.experimental.LazyApplication' and Robolectric makes no guarantees if a test modifies this field during execution. Replacing 'application' with 'getApplication()' resolves this deprecation warning.
Warning: "'assertEquals()' can be simplified to 'assertNull()'"
Warning: "Variable 'commentResponse' is never used"
Warning: "Typo: In word 'Reponse'"
Warnings: - "Unchecked cast: Class<*>! to Class<XMLRPCRequest>" - "Unchecked cast: Any! to Response<Any>"
Warnings: "Typo: In word 'udpated'"
Warnings: - "Inner class 'CommentsWPComRestResponse' may be 'static'" - "Inner class 'Post' may be 'static'" - "Inner class 'Author' may be 'static'"
FYI: 'n-a' stands for 'nullability annotations'. PS: This 'NotNullFieldNotInitialized' warning got suppressed because a 'response' class can never have its fields initialized via a constructor initialization, or otherwise for that matter.
645d3a5
to
2e855cd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't finished review yet, leaving some comments to start discussion though.
throw IllegalStateException( | ||
"Either post or reply must be not null and both can't be not null at the same time!" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will likely crash client apps in production if this scenario happens - clients don't have possibility to handle this exception. Can we change it to a log and failed OnCommentChange
event?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👋 @wzieba and thanks for this comment, this is indeed an interesting one, let me explain:
- First, you can take a look at this commit's description: 53e14a0
- From there, you will notice that I did that because the two
RemoteCreateCommentPayload
constructors are also defined as such and thus the callers should also respect their contract in order to avoid any NPE or an illegal app state. I also chose to keep thepayload.reply == null
condition and add the extrapayload.post == null
condition because thepayload.reply == null
condition was already present. - So, all in all, we should never reach this
else
case and thus if we do it is end-up being an illegal state of the app. Instead of trying to hide this state and somehow mute it I think it is better to throw an exception, that is, if and whenever someone changes how theRemoteCreateCommentPayload
is constructed, because if they don't, as it is now, it will never happen anyway.
Does that makes sense? 🙏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the two RemoteCreateCommentPayload constructors are also defined as such and thus the callers should also respect their contract in order to avoid any NPE or an illegal app state
Thanks. When writing this comment, I was under the impression that RemoteCreateCommentPayload
is a mapped response from the API. But then I looked at WordPress-Android
codebase and understood, that it's a request created via constructor. Let's keep the exception, then!
} | ||
} | ||
|
||
private long getPrioritizedRemoteCommentId(@NonNull RemoteCommentPayload payload) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the motivation behind this method? Are we sure it's valid to use remoteCommentId
if comment
is null? It seems to change a logic of many methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First all all, thanks for this comment @wzieba ! 💯
As discussed, this was done to avoid duplication on having the same logic with the REST
and XMLRPC
clients themselves, and also risking it be on one of the clients and not the other.
FYI:
👋 @wzieba and thanks for starting the review and any discussion on the changes, looking forward for us to finish the review! 🙇 ❤️ |
example/src/test/java/org/wordpress/android/fluxc/common/CommentsMapperTest.kt
Outdated
Show resolved
Hide resolved
authorProfileImageUrl = if (allowNulls) null else "https://gravatar.com/avatar/111222333", | ||
postTitle = if (allowNulls) null else "again", | ||
remoteSiteId = 100_000L, | ||
authorUrl = if (allowNulls) "" else "https://test-debug-site.wordpress.com", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the motivation behind assigning empty string to these fields instead of null
? null
is a valid value for many fields in CommentEntity
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question @wzieba ! 👍
Briefly, this is done because otherwise this test suite will fail due to the fact that a some fields on the CommentWPComRestResponse
are now defined as @NonNull
. Let me explain:
- You can try and change
authorUrl = if (withEmpty) "" else "https://test-debug-site.wordpress.com",
toauthorUrl = if (withEmpty) null else "https://test-debug-site.wordpress.com",
and see one test failing. - Now, in order to fix that you would need to update
URL = entity.authorUrl ?: ""
toURL = entity.authorUrl ?: null
. - However, you will quickly notice that this is not compiling due to the fact that
Author.URL
is defined as@NonNull
onCommentWPComRestResponse
.
Does that make sense? 🙏
Also, this 'SameParameterValue' warning got suppressed for the 'getDefaultCommentList(...)' function as it is currently being used once and as 'getDefaultCommentList(false)'. How this doesn't mean it will not be used in the future, or wasn't used in the past. As such, keeping this method signature and suppressing this warning for the time being seems to be the better approach here. Related PR Comment: https://github.com/wordpress-mobile/ WordPress-FluxC-Android/pull/2868#discussion_r1362018044
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for answering the questions @ParaskP7 , looks good to me! I've tested the change on the FluxC example and Jetpack apps and haven't spotted any crashes/problems.
Awesome @wzieba , thanks for reviewing, testing and raising all those questions, you rock! 🙇 ❤️ 🚀 |
Parent #2798
This PR adds any missing nullability annotation to CommentRestClient.java and CommentXMLRPCClient.java, all its related response classes and anything in between (ie.
CommentStore
). See response classes below:FYI.1: This change is
safe
, meaning that there shouldn't be any (major) compile-time changes associated with this change. Having said that, testing is highly recommended since the changes in this PR can affect one or more clients (ie. JP/WPAndroid, WCAndroid, etc)FYI.2: An analysis on
CommentStore
and its usages with our main clients suggests that this store is only being utilizing by JP/WPAndroid. AFAIA WCAndroid is not using that store and as such can be safely ignored from testing.PS: Note that CommentStore.java and their respective network client classes, both
REST
andXMLRPC
, seem to be deprecated. The CommentsStore.kt and their respective network client classes, bothREST
andXMLRPC
, seem to be the ones that are actually being actively used atm. Also note that the CommentWPComRestResponse.java response is shared between those two stores. As such, it seems that all comment related API calls from JP/WPAndroid are currently flowing via the new CommentsStore.kt, while only FluxC is using the deprecated CommentStore.java. Be mindful of all that when testing this PR. 🤷@wzieba let me know how I did on this PR, that is, in terms of updating these network client classes and adding nullability annotations on them and their main
CommentWPComRestResponse
response class, in order to utilize the nullability annotations added on its fields and thus make its use null proof. If you also feel that this is a good way to proceed with such client PRs, I'll then use this pattern across the board and follow a similar approach on every such PR.Nullability Annotation List:
Nullability Checks List:
Warnings Resolutions List:
Warnings Suppression List:
Refactor List:
Test List:
Associated Clients
It is highly recommending that this change is being tested on the below associated clients:
To Test (
REST
):FluxC Example
app via theCOMMENTS
screen. Verify everything is working as expected.CommentStore
related functionality on both, the WordPress and Jetpack apps, and see if everything is working as expected. For a couple of examples, you can expand and follow the inner and more explicit test steps within:To Test (
XMLRPC
):FluxC Example
app via theCOMMENTS
screen. Verify everything is working as expected.CommentStore
related functionality on both, the WordPress and Jetpack apps, and see if everything is working as expected. For a couple of examples, you can expand and follow the inner and more explicit test steps within:1. Comment Details Screen from Comments Screen [CommentDetailFragment.java]
ℹ️ This test applies to both, the
Jetpack
andWordPress
app.Comments
screen and tap on any comment.Comment Details
screen is shown and functioning as expected.2. Comment Details Screen from Notification Tab [CommentDetailFragment.java]
ℹ️ This test applies to the
Jetpack
app only.Notifications
tab, then itsCOMMENTS
sub-tab, and tap on any comment.Comment Details
screen is shown and functioning as expected.3. Edit Comment Screen from Comments Screen [UnifiedCommentsEditActivity.java]
ℹ️ This test applies to both, the
Jetpack
andWordPress
app.Comments
screen and tap on any comment.More
on the right side, at the bottom of the comment, selectEdit
.Edit Comment
screen is shown and functioning as expected.Name
,Web address
,Email address
and itsComment
itself.4. Edit Comment Screen from Notification Tab [UnifiedCommentsEditActivity.java]
ℹ️ This test applies to the
Jetpack
app only.Notifications
tab, then itsCOMMENTS
sub-tab, and tap on any comment.More
on the right side, at the bottom of the comment, selectEdit
.Edit Comment
screen is shown and functioning as expected.Name
,Web address
,Email address
and itsComment
itself.5. Reader Comments Screen [ReaderCommentListActivity.java]
ℹ️ This test applies to the
Jetpack
app only.Reader
tab, then itsDISCOVER
sub-tab, and tap on any post.Comments
button at the bottom of the post.Reader Comments
screen is shown and functioning as expected.