Cannot inherit from non-open class 'List' outside of its defining module
ro-lo opened this issue · 19 comments
In Swift 3 there are two new access levels on classes and functions. Public classes (as all these are) are not allowed to be subclassed outside of the defining module.
I was hoping to subclass some of the classes provided in this repository and am unable to do this. I have noticed that the develop branch has changes for this. Do you have a timeframe as to when this may become available on the master branch?
Thanks for your assistance.
Yes, the develop branch will become the master branch as soon as STU-3 has been published. This should be the case within a month or two.
There are no plans to backport these changes to DSTU-2; do you need DSTU-2?
Yes, that's the plan with versioning. Actually, version 2.9 has been out a while, I guess I could push that Pod – I'm not using Pods myself so I keep forgetting. Having trouble getting that version to build right now, though.
I won't get to take a closer look as to why 2.9 doesn't work with CocoaPods, it does work in Xcode directly. My advice (since you seem to be new to FHIR and have no requirement to use DSTU-2) would be to use 2.9 or the develop branch, see here for details.
First, if the latest develop
branch works for you, then use that one. It's currently on FHIR v1.8 (and I should tag this as 2.10) and will soon move to FHIR v1.9.
While version 2.9 has not (yet) been pushed to CocoaPods, it has been tagged in the repository. You should be able to see the tags in any modern git UI (like Fork for Mac). On the command line you can checkout tags like the version tag with git checkout 2.9.0
. You can also see all version tags on Github in the releases tab.
I have a couple more questions after spending some time with the develop branch where you can subclass one of the models you provide (in this case the List class). I'm not sure this is the right place to ask or not, if not I apologize, I'm new to GitHub (on top of FHIR and Swift).
The JSON I'm tasked with parsing has custom Resource Types that it looks as though I have no ability to use with the current Swift-FHIR implementation. I was hoping tho sublcass the List class (and others) where the main difference is the resourceType and have the parsing of the JSON automatically create those types of objects each time I encounter them. Below is an example of the JSON I'm trying to parse:
{
"resourceType": "Bundle",
"entry": [
{
"resource": {
"resourceType": "ActivityOverviewList",
"status": "current",
"mode": "working",
"title": "Radiology activities",
...
}
} ]
}
In the current implementation it appears as though the factory method only allows me to parse that specific set of resources only and it doesn't allow me to subclass my own resourceTypes. Is this true and I would be unable to do this with the current implementation or is my lack of knowledge in FHIR preventing me from understanding how I would do this?
Thanks for your help and my apologies if this is not the right place for a question like this.
This is the perfect place to ask these questions!
First, it looks like you're using a custom resource, which is a very unusual thing to do in FHIR. More typically you would profile an existing resource, in your case a List
. Is there a reason you guys can't use a profile on List? Then resourceType
would stay the same, but you'd have to re-instantiate those resources in your subclass yourself. Which brings up
secondly, resources contained in a Bundle get instantiated via a factory, which has all classes hardcoded into it as you've already discovered. It would be a good idea to allow the factory to
- use custom subclasses if a resource conforms to a specific profile, and
- allow to hook in for custom resources.
But this would need to be built, right now this is not possible. Before thinking about how that should work, can you let me know whether you're using a profile (good) or you use custom resources (should be avoided)?
OK so I'm going to take a stab and suggest maybe yes that we are using a profile... or maybe are supposed to be or something along those lines. By that I'm guessing using a profile is the profile tag inside of the meta tag in a resource? Further expanding the example JSON I referenced is as follows:
{
"resourceType": "Bundle",
"entry": [
{
"resource": {
"resourceType": "ActivityOverviewList",
"meta": {
"profile": [
"activityOverviewList"
]
},
"extension": [
{
"url": "#defaultList",
"valueBoolean": false
}
],
"status": "current",
"mode": "working",
"title": "Radiology activities",
...
}
} ]
}
Is that what you mean by profile? If yes... should the resourceType attribute then be set to List and somehow the subclass that I create of ActivityOverviewList eventually be instantiated based on maybe a cast of the entries in a bundle? I'm guessing perhaps the demo JSON they gave us may be a little wonky if this is actually the case with this profile. This being said my colleague who's basically doing the same thing on the Android side is using something called HAPI FHIR and he was able to create subclasses, register them as custom types, and set the default type for the profile appropriately. Is this possible in this implementation? Here's an example of what I mean:
fhirContext.registerCustomType(ActivityOverviewList.class);
fhirContext.registerCustomType(TaskList.class);
fhirContext.setDefaultTypeForProfile("activityOverviewList", ActivityOverviewList.class);
fhirContext.setDefaultTypeForProfile("TaskList", TaskList.class);
Thanks so much for your help. I really appreciate it!
Hi @ro-lo ,
FYI you probably need to change the annotation on your custom resource types a bit.
What you should have is a @ResourceDef
annotation with a profile URL and not a name, instead of a name. Basically, when your resource looks like this:
{
"resource": {
"resourceType": "ActivityOverviewList",
"meta": {
"profile": [
"activityOverviewList"
]
},
..you're actually creating a new custom resource type called "ActivityOverviewList" as opposed to a profile on List, and it's basically guaranteed to not be interoperable with other systems unfortunately.
If you instead use a resourcedef like
@ResourceDef(profile="http://some-url-for-your-profile")
public class ActivityOverviewList extends ListResource {
you'll get a serialization like:
{
"resource": {
"resourceType": "List",
"meta": {
"profile": [
"http://some-url-for-your-profile"
]
},
This is a profile on List, so the Swift library will be able to load it.
Thanks James! That leaves a feature request, the Swift library does not currently allow to use custom classes for resources conforming to a given profile. That is definitely functionality to add!
Thanks for the info James. The definition of the extended class actually does have this on the Java side so does that mean it is a profile on List? See here:
@ResourceDef(name = "ActivityOverviewList", profile = "activityOverviewList")
public class ActivityOverviewList extends ListResource {
Does the profile need to be a valid URL that returns some sort of definition or is it just a random string that can be used? Am I somehow able to parse the example JSON that I've referenced using these Swift-FHIR libraries today?
I appreciate the education into all of this and do hope there is a way of parsing this using these models. I'm assuming the parsing would however work if the JSON was more like the following?
{
"resourceType": "Bundle",
"entry": [
{
"resource": {
"resourceType": "List",
"meta": {
"profile": [
"activityOverviewList"
]
},
"extension": [
{
"url": "#defaultList",
"valueBoolean": false
}
],
"status": "current",
"mode": "working",
"title": "Radiology activities",
...
}
} ]
}
Would the parsing work properly then and I could inspect the >meta and >profile attributes in order to determine what type of List it is?
I'm hoping there is a way to use these models (even if it's to change the resourceType in the JSON to manage this. Do you know how I'd do this?
Thanks
The thing you'll need to do in order to make that class be a profile on List is to drop the name attribute, e.g.
@ResourceDef(profile = "activityOverviewList")
public class ActivityOverviewList extends ListResource {
Technically the profille should be a URL also.. Using a string will technically work (I'm sure the Swift library will parse it just fine, and I know HAPI will) but that field maps to Resource.meta.profile
which has a datatype of uri
. If you try to validate an instance with a non-URI profile identifier, the validator will probably flag that as an issue.
Assuming you're indeed using a Profile on List
rather than a custom resource, then you'll be able to parse the resource with this library as soon as the resourceType
error is fixed, yes. As James said, the profile URL is expected to be a real URL (and should resolve but the library won't check that).
Currently you'll have to re-instantiate the resources in your subclass yourself, you will receive standard List
instances from the framework. But since this is Swift, can't you use an extension on List
rather than a subclass? Your resource JSON won't have additional properties anyway.
As soon as the resourceType
error is fixed meaning what? Maybe I'm a bit lost here as I'm not following what error you mean on resourceType
.
So providing my JSON coming back is generated from a Profile on List
the JSON coming back would in fact have resourceType
set to List
and the Swift-FHIR library would properly process the response. I get that now.
Thanks so much both of you for your assistance, I think I'm finally starting to wrap my head around this stuff.
Yes, you got that right. "resourceType": "ActivityOverviewList"
is wrong if you're using a profile, it must still say "resourceType": "List"
plus identify the profile in meta
. Once this is back at List
, the library will instantiate a List
object that you can then work with.
Subclasses are another thing. Not currently supported in this framework while HAPI supports it. I'd think you can get away with an extension on List
but can only guess. 😃
Good luck!
@jamesagnew, I note that the RestfulServer to add a constraint to limit multiple resource providers to link a same resource type. Currently, we have a multiple subclasses of List, such as ActivityOverviewList, ConferenceList and so on. For these subclasses, we want to use the their own resource name to do the related restful fhir operation, such as GET ../ActivityOverviewList/, GET ../ConferenceList/ and so on. But the restfulServer dose not allowed them, I'm not clear why there is a limit constraint and do we need to add their own profile?
Creating a server which accepts GET /ActivityOverviewList
is not valid in FHIR. The list resource needs to be accessed using GET /List
.
If you use a profile as described above though, you can find instances of List on the server which implement that profile by calling GET /List?_profile=http://the.profile.url
Closing this issue since data models are now all open
, which addresses the original problem.