Using the java checker framework, why is a Map NonNull value not accepted into a Map Nullable value location?
With this code invocation:
schema.validate(
MapMaker.makeMap(
new AbstractMap.SimpleEntry<>(
"foo",
"baz"
),
new AbstractMap.SimpleEntry<>(
"bar",
2
)
),
configuration
);
I get this error:
java: [argument] incompatible argument for parameter arg of validate.
found : @Initialized @NonNull Map<@Initialized @NonNull String, @Initialized @NonNull Object>
required: @Initialized @NonNull Map<@Initialized @NonNull String, @Initialized @Nullable Object>
And the validate method is defined as:
public FrozenMap<@Nullable Object> validate(Map<String, @Nullable Object> arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException {
Any non null Object is a subset of the set of nullable Objects, so why does this not work? How do I get this to work for non-nullable key input also? Do I need to have a different input method signature for the nullable and the non-nullable input arg?
My arguments passed in to the validate method will be used for reading only. Per the checker framework javadocs, @Covariant may be a solution here:
For example, consider Iterator. A client can read elements but not write them, so Iterator<@Nullable String> can be a subtype of Iterator<String> without introducing a hole in the type system. Therefore, its type parameter is annotated with @Covariant. The first type parameter of Map.Entry is also covariant. Another example would be the type parameter of a hypothetical class ImmutableList.
But that only applies to interfaces.
So this is happening because the checker framework sees
So the solutions here are to:
public FrozenMap<@Nullable Object> validate(Map<String, ? extends @Nullable Object> arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException {
Map<String, ?>
This is not great because type checking info is lost from the signatureMap<String, @Nullable Object> arg
Map<String, Object> arg
Number 4 example code would look like
@Covariant(0)
public interface MapValidator <InType extends @Nullable Object, OutType> {
OutType validate(Map<String, InType> arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException;
}
public class SomeSchema implements MapValidator<@Nullable Object, FrozenMap<@Nullable Object>> {
OutType validate(Map<String, @Nullable Object> arg, SchemaConfiguration configuration) throws ValidationException, InvalidTypeException {
...
}
}