user2741287 user2741287 - 1 year ago 51
Scala Question

Java Wildcard Generic Type Interop From Scala

I'm writing in scala and I'm dealing with a Java API which returns a

List<? extends IResource>
, where
is a generic parent interface (the details, if it helps).

I'm trying to add an
to the list returned by that method, but I can't get my code to compile (
is a java class which implements
, and getContainedResources returns the
List<? extends IResource>

Here is my original code

val patient = new Patient()
val patientASResource: IResource = patient

And here is the error I get:

type mismatch;
found : patientASResource.type (with underlying type ca.uhn.fhir.model.api.IResource)
required: ?0 where type ?0 <: ca.uhn.fhir.model.api.IResource
one error found

Notice that I'm trying to add
which I've typed-up to the interface
. Trying to add
(the class implementing the interface) has a worse error message.

Other things I've tried:

//From what I understand of "Java wildcards" per here:
type Col = java.util.Collection[_ <: IResource]
val resList: Col = entry.getResource.getContained.getContainedResources
val lst: Col = asJavaCollection(List(patient))

Doesn't work either, it returns something like:

type mismatch
found : java.util.Collection[_$1(in method transformUserBGs)] where type _$1(in method transformUserBGs) <: ca.uhn.fhir.model.api.IResource
required: java.util.Collection[_ <: _$1(in type Col)]

Answer Source

The problem isn't with interop. This definitely shouldn't compile, and neither should the equivalent Java code.

List<? extends IResource> means it can be a List<IResource>, List<Patient>, List<SomeSubclassOfPatient>, List<SomeOtherResourceUnrelatedToPatient>, etc. and you don't know which. Thus, adding a Patient (or an IResource after upcasting) to such a list is not allowed.

If you somehow know that in your specific situation entry is such that entry.getResource.getContained.getContainedResources returns a List[IResource], or a List[Patient], you should attempt to ensure this statically by specifying this when overriding getContainedResources. If this is impossible, the last recourse is to cast:


Just to reiterate: you should avoid this if at all possible.