[ 
https://issues.apache.org/jira/browse/COLLECTIONS-891?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Ruiqi Dong updated COLLECTIONS-891:
-----------------------------------
    Description: 
*Summary*
`IndexedCollection` is still a `Collection`, so `contains( x )` should answer 
whether an equal object is present in the collection.
 
The current implementation answers a different question: whether the collection 
contains *any* element whose transformed key matches `keyTransformer.apply( x 
)`.

That produces false positives whenever two different objects map to the same 
key.
 
*Affected code*
File: 
`src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java`
{code:java}
@SuppressWarnings("unchecked")
@Override
public boolean contains(final Object object) {
    return index.containsKey(keyTransformer.apply((C) object));
} {code}
*Reproducer*
Add the following test to 
`src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java`:
{code:java}
@Test
void testContainsUsesObjectEqualityNotOnlyTransformedKey() {
    final Collection<String> coll = makeUniqueTestCollection();
    coll.add("01");

    assertFalse(coll.contains("1"));
} {code}
This uses the existing `IntegerTransformer`, so both `"01"` and `"1"` map to 
the same key `1`, but the objects are not equal.
 
Run:
{code:java}
mvn -q 
-Dtest=org.apache.commons.collections4.collection.IndexedCollectionTest#testContainsUsesObjectEqualityNotOnlyTransformedKey
 test {code}
*Observed behavior*
{code:java}
expected: <false> but was: <true> {code}
*Expected behavior*
`contains("1")` should be `false`, because only `"01"` was added to the 
collection.
 
The class is a `Collection` decorator, not just a key index. Its `contains` 
method must preserve collection membership semantics. Matching on transformed 
keys instead of object equality breaks the `Collection.contains` contract 
whenever the transformer is not injective.

  was:
*Summary*
`IndexedCollection` is still a `Collection`, so contains(x) should answer 
whether an equal object is present in the collection.
 
The current implementation answers a different question: whether the collection 
contains *any* element whose transformed key matches `keyTransformer.apply(x)`.

That produces false positives whenever two different objects map to the same 
key.
 
*Affected code*
File: 
`src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java`
{code:java}
@SuppressWarnings("unchecked")
@Override
public boolean contains(final Object object) {
    return index.containsKey(keyTransformer.apply((C) object));
} {code}
*Reproducer*
Add the following test to 
`src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java`:
{code:java}
@Test
void testContainsUsesObjectEqualityNotOnlyTransformedKey() {
    final Collection<String> coll = makeUniqueTestCollection();
    coll.add("01");

    assertFalse(coll.contains("1"));
} {code}
This uses the existing `IntegerTransformer`, so both `"01"` and `"1"` map to 
the same key `1`, but the objects are not equal.
 
Run:
{code:java}
mvn -q 
-Dtest=org.apache.commons.collections4.collection.IndexedCollectionTest#testContainsUsesObjectEqualityNotOnlyTransformedKey
 test {code}
*Observed behavior*
{code:java}
expected: <false> but was: <true> {code}
*Expected behavior*
`contains("1")` should be `false`, because only `"01"` was added to the 
collection.
 
The class is a `Collection` decorator, not just a key index. Its `contains` 
method must preserve collection membership semantics. Matching on transformed 
keys instead of object equality breaks the `Collection.contains` contract 
whenever the transformer is not injective.


> IndexedCollection.contains() can return true for objects that were never added
> ------------------------------------------------------------------------------
>
>                 Key: COLLECTIONS-891
>                 URL: https://issues.apache.org/jira/browse/COLLECTIONS-891
>             Project: Commons Collections
>          Issue Type: Bug
>          Components: Collection
>            Reporter: Ruiqi Dong
>            Priority: Minor
>
> *Summary*
> `IndexedCollection` is still a `Collection`, so `contains( x )` should answer 
> whether an equal object is present in the collection.
>  
> The current implementation answers a different question: whether the 
> collection contains *any* element whose transformed key matches 
> `keyTransformer.apply( x )`.
> That produces false positives whenever two different objects map to the same 
> key.
>  
> *Affected code*
> File: 
> `src/main/java/org/apache/commons/collections4/collection/IndexedCollection.java`
> {code:java}
> @SuppressWarnings("unchecked")
> @Override
> public boolean contains(final Object object) {
>     return index.containsKey(keyTransformer.apply((C) object));
> } {code}
> *Reproducer*
> Add the following test to 
> `src/test/java/org/apache/commons/collections4/collection/IndexedCollectionTest.java`:
> {code:java}
> @Test
> void testContainsUsesObjectEqualityNotOnlyTransformedKey() {
>     final Collection<String> coll = makeUniqueTestCollection();
>     coll.add("01");
>     assertFalse(coll.contains("1"));
> } {code}
> This uses the existing `IntegerTransformer`, so both `"01"` and `"1"` map to 
> the same key `1`, but the objects are not equal.
>  
> Run:
> {code:java}
> mvn -q 
> -Dtest=org.apache.commons.collections4.collection.IndexedCollectionTest#testContainsUsesObjectEqualityNotOnlyTransformedKey
>  test {code}
> *Observed behavior*
> {code:java}
> expected: <false> but was: <true> {code}
> *Expected behavior*
> `contains("1")` should be `false`, because only `"01"` was added to the 
> collection.
>  
> The class is a `Collection` decorator, not just a key index. Its `contains` 
> method must preserve collection membership semantics. Matching on transformed 
> keys instead of object equality breaks the `Collection.contains` contract 
> whenever the transformer is not injective.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to