-
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?
Changes from all commits
b83bd89
508227c
01003bf
da96e8b
8e8fd6c
fd8dc5e
0c15467
57e4268
a480d1e
f973a3d
053855f
4beef3a
3e407f6
de9f3d9
db865ee
d0bad35
6d7a100
8e36dce
8ab77ec
d50700f
484872b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ | |
import io.jsonwebtoken.lang.Strings; | ||
|
||
import java.util.Collection; | ||
import java.util.Iterator; | ||
import java.util.LinkedHashSet; | ||
|
||
public class DefaultCollectionMutator<E, M extends CollectionMutator<E, M>> implements CollectionMutator<E, M> { | ||
|
@@ -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 commentThe 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. Such a subclass could also be more efficient, potentially using a 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? |
||
if (doAdd(e)) changed(); | ||
boolean doReplace = false; | ||
|
||
// Replacement step 1: iterate until element to replace (if any) | ||
E item; | ||
Iterator<E> it = this.collection.iterator(); | ||
while (it.hasNext()) { | ||
item = it.next(); | ||
|
||
// Same item, nothing to do | ||
if (item.equals(e)) | ||
return self(); | ||
|
||
boolean bothIdentifiable = e instanceof Identifiable && item instanceof Identifiable; | ||
boolean sameId = bothIdentifiable && ((Identifiable) item).getId().equals(((Identifiable) e).getId()); | ||
if (sameId) { | ||
it.remove(); // step 2: remove existing item | ||
doReplace = true; | ||
break; | ||
} | ||
} | ||
|
||
if (doReplace) { | ||
// Replacement step 3: collect and remove elements after element to replace | ||
Collection<E> elementsAfterExisting = new LinkedHashSet<>(); | ||
while (it.hasNext()) { | ||
elementsAfterExisting.add(it.next()); | ||
it.remove(); | ||
} | ||
|
||
this.doAdd(e); // step 4: add replacer element (position will be at the existing item) | ||
this.collection.addAll(elementsAfterExisting); // step 5: add back the elements found after existing item | ||
|
||
changed(); // trigger changed() | ||
} | ||
else { | ||
// No replacement, do add instead | ||
if (doAdd(e)) changed(); | ||
} | ||
|
||
return self(); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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 commentThe 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 Additionally, if we changed Based on this, we don't want to override |
||
if (this == obj) { | ||
return true; | ||
} | ||
if (obj instanceof DefaultMacAlgorithm) { | ||
DefaultMacAlgorithm other = (DefaultMacAlgorithm) obj; | ||
return super.equals(obj) && this.minKeyBitLength == other.minKeyBitLength; | ||
} | ||
return false; | ||
} | ||
} |
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.