-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,6 @@ | |
*/ | ||
package com.github.benmanes.caffeine.cache; | ||
|
||
import org.checkerframework.checker.nullness.qual.NonNull; | ||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
||
/** | ||
|
@@ -26,13 +25,13 @@ | |
public interface BasicCache<K, V> { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
ben-manes
Author
Owner
|
||
|
||
/** Returns the value stored in the cache, or null if not present. */ | ||
@Nullable V get(@NonNull K key); | ||
@Nullable V get(K key); | ||
|
||
/** Stores the value into the cache, replacing an existing mapping if present. */ | ||
void put(@NonNull K key, @NonNull V value); | ||
void put(K key, V value); | ||
|
||
/** Removes the entry from the cache, if present. */ | ||
void remove(@NonNull K key); | ||
void remove(K key); | ||
|
||
/** Invalidates all entries from the cache. */ | ||
void clear(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,6 @@ | |
import java.util.function.BiFunction; | ||
import java.util.function.Function; | ||
|
||
import org.checkerframework.checker.nullness.qual.NonNull; | ||
import org.checkerframework.checker.nullness.qual.Nullable; | ||
|
||
/** | ||
|
@@ -50,7 +49,7 @@ public interface AsyncCache<K, V> { | |
* @throws NullPointerException if the specified key is null | ||
*/ | ||
@Nullable | ||
CompletableFuture<V> getIfPresent(@NonNull K key); | ||
CompletableFuture<V> getIfPresent(K key); | ||
|
||
/** | ||
* Returns the future associated with {@code key} in this cache, obtaining that value from | ||
|
@@ -70,9 +69,7 @@ public interface AsyncCache<K, V> { | |
* @return the current (existing or computed) future value associated with the specified key | ||
* @throws NullPointerException if the specified key or mappingFunction is null | ||
*/ | ||
@NonNull | ||
CompletableFuture<V> get(@NonNull K key, | ||
@NonNull Function<? super K, ? extends V> mappingFunction); | ||
CompletableFuture<V> get(K key, Function<? super K, ? extends V> mappingFunction); | ||
|
||
/** | ||
* Returns the future associated with {@code key} in this cache, obtaining that value from | ||
|
@@ -95,9 +92,8 @@ CompletableFuture<V> get(@NonNull K key, | |
* @throws RuntimeException or Error if the mappingFunction does when constructing the future, | ||
* in which case the mapping is left unestablished | ||
*/ | ||
@NonNull | ||
CompletableFuture<V> get(@NonNull K key, | ||
@NonNull BiFunction<? super K, Executor, CompletableFuture<V>> mappingFunction); | ||
CompletableFuture<V> get(K key, | ||
BiFunction<? super K, Executor, CompletableFuture<V>> mappingFunction); | ||
This comment has been minimized.
Sorry, something went wrong.
vlsi
Contributor
|
||
|
||
/** | ||
* Returns the future of a map of the values associated with {@code keys}, creating or retrieving | ||
|
@@ -122,9 +118,8 @@ CompletableFuture<V> get(@NonNull K key, | |
* @throws RuntimeException or Error if the mappingFunction does so, in which case the mapping is | ||
* left unestablished | ||
*/ | ||
@NonNull | ||
CompletableFuture<Map<K, V>> getAll(@NonNull Iterable<? extends @NonNull K> keys, | ||
@NonNull Function<Set<? extends @NonNull K>, @NonNull Map<K, V>> mappingFunction); | ||
CompletableFuture<Map<K, V>> getAll(Iterable<? extends K> keys, | ||
Function<Set<? extends K>, Map<K, V>> mappingFunction); | ||
This comment has been minimized.
Sorry, something went wrong.
vlsi
Contributor
|
||
|
||
/** | ||
* Returns the future of a map of the values associated with {@code keys}, creating or retrieving | ||
|
@@ -149,9 +144,8 @@ CompletableFuture<Map<K, V>> getAll(@NonNull Iterable<? extends @NonNull K> keys | |
* @throws RuntimeException or Error if the mappingFunction does so, in which case the mapping is | ||
* left unestablished | ||
*/ | ||
@NonNull | ||
CompletableFuture<Map<K, V>> getAll(@NonNull Iterable<? extends @NonNull K> keys, | ||
@NonNull BiFunction<Set<? extends @NonNull K>, Executor, CompletableFuture<Map<K, V>>> mappingFunction); | ||
CompletableFuture<Map<K, V>> getAll(Iterable<? extends K> keys, | ||
BiFunction<Set<? extends K>, Executor, CompletableFuture<Map<K, V>>> mappingFunction); | ||
|
||
/** | ||
* Associates {@code value} with {@code key} in this cache. If the cache previously contained a | ||
|
@@ -165,7 +159,7 @@ CompletableFuture<Map<K, V>> getAll(@NonNull Iterable<? extends @NonNull K> keys | |
* @param valueFuture value to be associated with the specified key | ||
* @throws NullPointerException if the specified key or value is null | ||
*/ | ||
void put(@NonNull K key, @NonNull CompletableFuture<V> valueFuture); | ||
void put(K key, CompletableFuture<V> valueFuture); | ||
|
||
/** | ||
* Returns a view of the entries stored in this cache as a thread-safe map. Modifications made to | ||
|
@@ -182,8 +176,7 @@ CompletableFuture<Map<K, V>> getAll(@NonNull Iterable<? extends @NonNull K> keys | |
* | ||
* @return a thread-safe view of this cache supporting all of the optional {@link Map} operations | ||
*/ | ||
@NonNull | ||
ConcurrentMap<@NonNull K, @NonNull CompletableFuture<V>> asMap(); | ||
ConcurrentMap<K, CompletableFuture<V>> asMap(); | ||
|
||
/** | ||
* Returns a view of the entries stored in this cache as a synchronous {@link Cache}. A mapping is | ||
|
@@ -193,6 +186,5 @@ CompletableFuture<Map<K, V>> getAll(@NonNull Iterable<? extends @NonNull K> keys | |
* | ||
* @return a thread-safe synchronous view of this cache | ||
*/ | ||
@NonNull | ||
Cache<K, V> synchronous(); | ||
} |
8 comments
on commit fb4eb0b
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 @vlsi! I didn't get to this today, but hoping to tomorrow as a day off. 🙂
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.
In general, @NonNull
removal looks good.
The's a common pattern with type variables. In other words, you might want to replace ClassName<K>
with ClassName<K extends Object>
to specify that K must not be nullable
.
Just in case, the following would mean both K
and K1
are never nullable, while both V
and V1
permit nullable types:
public static <K extends Object, V, K1 extends K, V1 extends V> Cache<K1, V1> build(Caffeine<K, V> builder) {
--
I would recommend (checker framework recommend that as well) placing @Nullable
, @PolyNull
, @NonNegative
closer to a type. At the end of the day, it is type
annotation rather than method
annotation.
For instance:
@NonNegative
public int frequency(@NonNull E e) {
=>
public @NonNegative int frequency(@NonNull 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.
I am not very comfortable with the CheckerFramework's nullness rules yet, so I guess this will take a few more iterations. I'm concerned that it will be wrong and cause problems downstream for those using it?
Now that CheckerFramework and ErrorProne are compatible, we could run both. Doing this locally shows various warnings that deserve a dedicated pass in a different commit.
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'm concerned that it will be wrong and cause problems downstream for those using it?
Kotlin does not understand CheckerFramework's nullness annotations (it treats the code as if it was not annotated), so you are covered there :)
The misuse of jsr305 nullables might cause Kotlin's compilation errors.
If someone is impacted by improper or incomplete nullness annotations (I assume they are verifying nullness), they can use astub
feature of the checker framework where they can augment the annotation of a third-party code.
So it does not hurt much to have incomplete or improper annotations.
IDEA does not support checkerframework's rules regarding generics, @PolyNull
, @MonotonicNonNull
and other complicated cases, so it might produce false positives. However, in my experience, even then nullness annotations help a lot. IDEA understands DefaultQualifier.
For instance, in Calcite we have a few stubs: https://github.com/apache/calcite/tree/master/src/main/config/checkerframework
A funny story is sometimes we use stubs to remove excessive @Nullable
annotations (e.g. https://github.com/apache/calcite/blob/f277a2468805999a446e5bcd0ef70aa1e9550562/src/main/config/checkerframework/guava/Function.astub)
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.
Okay, thanks a lot. After I go through a pass would you be open to doing a review and sending in a PR of changes?
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.
After I go through a pass would you be open to doing a review and sending in a PR of changes?
Sure.
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! I pushed to the v3 branch. The improved wildcard generics are nice, but I likely still have goofs wrt checker.
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.
fyi, I am also starting a v3-checker
branch where the checker framework plugin is enabled and will go through handing the warnings. That will be merged back into v3, but will take a while to resolve them all (so unlikely to be done soon).
Do you mean
BasicCache
should always be instantiated with anon-nullable
K
?If that is the case, then please use
BasicCache<K extends Object, V>
which literally meansK is a non-nullable Object
.By default,
BasicCache<K, V>
means it allows clients to use the interface as bothimplements BasicCache<@Nullable String, ..>
andBasicCache<@NonNull String, ...>
.If you use
BasicCache<K extends Object, V>
(orBasicCache<K extends @NonNull Object, V>
which is the same thing), then clients won't be able to implement the interface likeimplements BasicCache<@Nullable String, ...>
which is probably nice.By the way,
BasicCache<K extends @NonNull Object, V>
defeatsorg.jboss:jandex
annotation parser (see smallrye/jandex#99 ), so the less annotations the better.Just in case,
jandex
is used in Hibernate, so the net bytecode parsing result might be hard to understand.