-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Bugfix: Nested collection replacment #970
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
base: master
Are you sure you want to change the base?
Conversation
by combining remove and add into a single method. Handle null and empty by throwing NullPointerException and IllegalArgumentException respectively. Throws NoSuchElementException if the element to replace cannot be found. Method will rollback to previous element (before replacement) if either the remove step or add step fails.
Test happy path. Test null handling. Test empty handling. Test missing handling.
I had considered (but eventually decided against) an alternative behavior when Currently, it throws As an alternative, when no "similar" element is found, I would appreciate thoughts on this alternative. |
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 opening the PR @lhy-hoyin!
I've left a few overly verbose comments on the your PR, hopefully you find them helpful.
I know you proposed a new replace
method, and there still might be value in that, I'd suggest starting with a test that described the original problem in #961.
Basically, the docs say that .add()
should replace the any existing item, most importantly with Identifiable
objects. (e.g. where a user wants to replace an algorithm with a different implementation)
Again, thanks for taking the time to look into this issue!
impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultCollectionMutator.java
Outdated
Show resolved
Hide resolved
impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultCollectionMutator.java
Outdated
Show resolved
Hide resolved
impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultCollectionMutator.java
Outdated
Show resolved
Hide resolved
impl/src/main/java/io/jsonwebtoken/impl/lang/DefaultCollectionMutator.java
Outdated
Show resolved
Hide resolved
impl/src/test/groovy/io/jsonwebtoken/impl/lang/DefaultCollectionMutatorTest.groovy
Outdated
Show resolved
Hide resolved
Overloaded with a message and no-message variants.
In the case of Otherwise, when item is not In other words, the pseudocode would be like
Did I interpret correctly? |
Yes, possibly with the minor issue of equality. if |
Remove rollback code
I noticed that In I would like to implement @Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof DefaultMacAlgorithm) {
DefaultMacAlgorithm other = (DefaultMacAlgorithm) obj;
return super.equals(obj) && this.minKeyBitLength == other.minKeyBitLength;
}
return false;
} With the above implementation, I am able to pass all tests. |
to also check equality for minKeyBitLength, apart from ID and jcaName (both inherited from CryptoAlgorithm).
Add tests addIdentifiableWithSameIdEvictsExisting and replaceSameObject
add() is used instead of the previous replace(), but behaviour should still be the same.
Bug was that newElement is always added to the back of the collection regardless of the position of existingElement. Add unit test to check ordering after replace
@bdemers Would you be able to take a look and approve the PR before the end of the month? I am hoping for this PR to contribute to my hacktoberfest progress (which cuts off by the end of the month). |
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.
Sorry about the delay. We can try to wrap this up this week!
The current add
flow looks like it needs to iterate over the list twice (once to check if an item matches, and then again to do the replacement.
My suggestion would be to remove the public replace
method (use a private method if needed), since the main problem is the add(Identifiable)
use case.
That should reduce the complexity of the method/logic
to reduce code complexity. All tests passed.
@bdemers I have integrated the logic for replacement directly into
|
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 looks good!
Thank you!
…s due to failing Oracle JDK 17 download. (jwtk#981)
Use SPDX identifier in POMs This replaces the custom name with an SPDX identifier to enable tooling to automatically detect the correct license. See https://spdx.org/licenses/Apache-2.0.html
by combining remove and add into a single method. Handle null and empty by throwing NullPointerException and IllegalArgumentException respectively. Throws NoSuchElementException if the element to replace cannot be found. Method will rollback to previous element (before replacement) if either the remove step or add step fails.
Test happy path. Test null handling. Test empty handling. Test missing handling.
Overloaded with a message and no-message variants.
Remove rollback code
to also check equality for minKeyBitLength, apart from ID and jcaName (both inherited from CryptoAlgorithm).
Add tests addIdentifiableWithSameIdEvictsExisting and replaceSameObject
add() is used instead of the previous replace(), but behaviour should still be the same.
Bug was that newElement is always added to the back of the collection regardless of the position of existingElement. Add unit test to check ordering after replace
to reduce code complexity. All tests passed.
…yin/jjwt into lhy-hoyin-nested-collection-replace
@lhy-hoyin sorry for the long delay, but I rebased from |
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.
Overall a good PR! Nice work - just have some requested changes and comments.
* @param object the object to check | ||
* @throws IllegalArgumentException if the object is <code>null</code> or empty | ||
*/ | ||
public static void notEmpty(Object object) { |
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 just did a code search, and this method isn't used anywhere, so it's best to remove it, as well as the newly added notEmpty(Object, String)
method above.
@@ -222,4 +222,16 @@ protected boolean doVerify(VerifySecureDigestRequest<SecretKey> request) { | |||
byte[] computedSignature = digest(request); | |||
return MessageDigest.isEqual(providedSignature, computedSignature); | |||
} | |||
|
|||
@Override | |||
public boolean equals(Object obj) { |
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.
Ordinarily, I agree that sub-type checking with specific properties should be performed in sub-classes, but in this case, all crypto JWT algorithms are guaranteed to be uniquely defined by their ID (and JCA name), regardless of internal implementation details. (In this particular case, the minKeyBitLength
is really an internal convenience and not needed for algorithm equality check).
Additionally, if we changed DefaultMacAlgorithm
, we'd have to change every other subclass of the parent CryptoAlgorithm
and that could have far reaching consequences.
Based on this, we don't want to override equals
at all, so please remove this method.
@@ -48,7 +49,45 @@ private boolean doAdd(E e) { | |||
|
|||
@Override | |||
public M add(E e) { |
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 is a fairly complex implementation - it almost makes me think we should create a specific abstract subclass for Algorithm/ID-specific logic, e.g. AlgorithmCollectionMutator
or something like that.
Such a subclass could also be more efficient, potentially using a Set<String>
or a Set<String,Identifiable>
to keep track of what IDs exist already instead of iterating over the internal collection.
Finally, there's no method contract that collection element ordering will remain unchanged, so we don't need to perform step 3 - that will implicitly create a performance penalty by saving trailing elements and adding them back in to the end of the collection after replacing the found element.
Thoughts?
This commit
(1) fix #961 , where
DefaultCollectionMutator.add(E e)
does not overrides existingadd(E e)
will check forIdentifiable
with the sameID
incollection
. If there is, an in-place replacement (order not changed) is done and callschanged()
. Otherwise, itdoAdd
and callschanged()
.Nothing is done if
e
is the same object as the existing element.(2) Implement
DefaultMacAlgorithm.equals
All attributes need to be
equals
ID
(inherited fromCryptoAlgorithm
)jcaName
(inherited fromCryptoAlgorithm
)minKeyBitLength
New unit tests are also added.
Fixes: #961