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

JCache Cache.putAll(...) with immutable map can cause exception #841

Closed
wants to merge 1 commit into from

Conversation

kdombeck
Copy link
Contributor

Added test case showing that calling javax.cache.Cache.putAll(Map) with an immutable map causes a UnsupportedOperationException "if" the CacheWriter throws an exception. The problem with this is that you loose the original exception from the CacheWriter and thus do not know what the root cause was.

The issue appears to be with CacheProxy in that it tries to remove entries from the original map. Which in this case is immutable.

Seems like similar issue in CacheProxy.deleteAllToCacheWriter

I can change my code to be a mutable map but wanted to see what your thoughts were on this issue.

… an immutable map causes a UnsupportedOperationException "if" the CacheWriter throws an exception. The problem with this is that you loose the original exception from the CacheWriter and thus do not know what the root cause was.
@CLAassistant
Copy link

CLAassistant commented Dec 16, 2022

CLA assistant check
All committers have signed the CLA.

@@ -72,6 +73,19 @@
}
}

@Test
public void putAllImmutable_fails() {

Check warning

Code scanning / Pmd (reported by Codacy)

The instance method name 'putAllImmutable_fails' doesn't match '[a-z][a-zA-Z0-9]*'

The instance method name 'putAllImmutable_fails' doesn't match '[a-z][a-zA-Z0-9]*'
@ben-manes
Copy link
Owner

This is one of those JCache design surprises that is poorly documented and explained. In CacheWriter it states,

* @param entries a mutable collection to write. Upon invocation, it contains
*                the entries to write for write-through. Upon return the
*                collection must only contain entries that were not
*                successfully written. (see partial success above)

This is not stated on the Cache api, so I wasn't sure what the expectation is for the vendor (perform a copy or pass it in directly so that the caller can also inspect these results?). It looks like I thought this was required (either due to the TCK or forum discussions) and wrote a unit test to assert what I thought was required.

For the removeAll(keys) I did the defensive copy as that passes the latest TCK. When I add similar to putAll(map) it seems to pass now too, so I think it must be okay now to change this. When I run older TCKs a few tests fail (since it asserted buggy behavior of the spec lead's implementation divergences), but I can't tell if this was entirely my goof or what I felt forced into doing. Either way a mutable copy has to be made somewhere due to how their API was defined.

Set<K> keysToRemove = new HashSet<>(keys);
CacheWriterException e = deleteAllToCacheWriter(keysToRemove);

@ben-manes ben-manes closed this in ca98c54 Dec 16, 2022
@kdombeck
Copy link
Contributor Author

Thanks for the response. I completely missed that documentation.

I was looking at Cache.putAll(...) since that is the public interface most people will be using.

I must say I am a bit surprised to see a parameter being mutated thou since it seems fairly common for things to be immutable for caching. Thanks for pointing me to that documentation!!!

@ben-manes
Copy link
Owner

It is very convoluted. If the writer does not throw an exception then it is successful and we ignore any mutations done to entries (so all are put into the cache). If it is thrown, then the implementer must also mutate the mapping to communicate correctly for partial success. You would more typically see an exception carry this information, not the argument. Unfortunately another quirk is that CacheWriter is incompatible with the annotation-style AOP caching, since the synthetic key is a private data class of the spec's implementation. Also note that since it was rejected for inclusion by JEE and Jakarta, it seems to be a dead (jsr107/jsr107spec#415).

@ben-manes
Copy link
Owner

Released in 3.1.3

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.

3 participants