user2741287
user2741287

Reputation: 437

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 IResource is a generic parent interface (the details, if it helps).

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

Here is my original code

val patient = new Patient()
patient.setId(ID)
val patientASResource: IResource = patient
entry.getResource.getContained.getContainedResources.add(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
         entry.getResource.getContained.getContainedResources.add(patientASResource)
                                                                  ^
 one error found

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

Other things I've tried:

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

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)]
 resList.addAll(lst)
 ^

Upvotes: 1

Views: 192

Answers (1)

Alexey Romanov
Alexey Romanov

Reputation: 170733

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:

entry.getResource.getContained.
  getContainedResources.asInstanceOf[java.util.List[IResource]].add(patient)

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

Upvotes: 2

Related Questions