FHIR Chat · Class Generation for Profiles · hapi

Stream: hapi

Topic: Class Generation for Profiles


view this post on Zulip Chris Moesel (Aug 22 2018 at 19:56):

Does HAPI provide a code generator for automatically generating Java classes from FHIR profiles (StructureDefinitions)? I couldn't find any information suggesting that -- but someone told me it did.

view this post on Zulip Chris Moesel (Aug 22 2018 at 19:58):

I found a project from @Jens Villadsen here, but it looks like it is not complete and probably not maintained anymore.

view this post on Zulip Jens Villadsen (Aug 22 2018 at 20:07):

Haha - thats my own! It would actually be a part what I need, and I'm considering to resurrect it

view this post on Zulip Chris Moesel (Aug 22 2018 at 20:08):

Cool. I think that would be probably be useful to others as well!

view this post on Zulip Jens Villadsen (Aug 22 2018 at 20:09):

I would love some contributions to it ... but I'll guess it all starts with me getting back to it ;)

view this post on Zulip Chris Moesel (Aug 22 2018 at 20:11):

Yeah, I'm not sure we're in a position to contribute -- and can't even guarantee we'd use it if it was fully working. We're just evaluating some different approaches right now -- and that was one of them. Trying to see what is and is not viable.

view this post on Zulip Chris Moesel (Aug 22 2018 at 20:12):

We actually kind of more-so need something like that in JavaScript.

view this post on Zulip Grahame Grieve (Aug 22 2018 at 21:59):

it's been my intention to produce something like this

view this post on Zulip Jens Villadsen (Aug 23 2018 at 20:35):

I'll see if I can find the time to kickstart once again the next couple of days! Pull requests are more than welcome ;)

view this post on Zulip Sandro Zbinden (Dec 13 2019 at 09:37):

I see that the provided project from @Jens Villadsen has not been updated since a while? Is there still some other work going on? Are there any other projects / people working on it and have some experience to share? From a developer point of view I belive that generating classes from profiles would help interoperability, as it prevents errors or missuse of ressources. Thus I think it would be great to be able to create the Java classes or even Typescript classes from profiles. Maybe it could be done similarly like FHIR Proto's are generated?

view this post on Zulip Jens Villadsen (Dec 13 2019 at 09:49):

There has been very little activity in it for a long period of time. I would like to start it up again, but I won't do it if noone uses it or cares to contribute to it

view this post on Zulip Jens Villadsen (Dec 13 2019 at 09:49):

@Sandro Zbinden

view this post on Zulip Patrick Werner (Dec 13 2019 at 12:50):

may i ask what is the motivation behind this? Profiled resources are supported by hapi anyway and dont need special classes. Or is the motivation behind this to auto create facades to ease the creation of a profiled resource?

view this post on Zulip Frank Oemig (Dec 13 2019 at 16:21):

In my understanding it is generation of Java classes for arbitrary SDs in then end. Or am I wrong?

view this post on Zulip Michel Jacobs (Jan 15 2020 at 15:59):

Are there any updates about this?

For me it is the ease of the creation of profiled resources. since I'm working on profiled FHIRresource generation with Synthea. and not having to worry about making those classes by hand would help me immensely.

view this post on Zulip Patrick Werner (Jan 15 2020 at 16:03):

may i ask what is the motivation behind this? Profiled resources are supported by hapi anyway and dont need special classes. Or is the motivation to auto create facades to ease the creation of a profiled resource?

view this post on Zulip Erik Moll (Jan 15 2020 at 16:24):

Hi, I am working with Michel on this. The idea is to use the generated classes in Synthea for the mapping from Synthea structures to (profiled) FHIR resources, to have realistic FHIR test data for our systems. Synthea is already using the HAPI generated models / classes. It would be nice if we could use a set of profiled resources as used in certain regions (e.g. US core) or using our internal value sets, code maps, in Synthea.

view this post on Zulip Jens Villadsen (Jan 15 2020 at 17:42):

I agree

view this post on Zulip Jens Villadsen (Jan 15 2020 at 17:42):

It could be a way to discover changes in an IG

view this post on Zulip Jens Villadsen (Jan 15 2020 at 17:45):

So @Erik Moll / @Michel Jacobs should we restart this project of mine?

view this post on Zulip Grahame Grieve (Jan 15 2020 at 20:26):

I'm interested to know what your classes that represent profiles actually do

view this post on Zulip Jens Villadsen (Jan 15 2020 at 20:33):

There will be limitations of course - ... First thing would be ease of access to extension fields

view this post on Zulip Jens Villadsen (Jan 15 2020 at 20:34):

type safety

view this post on Zulip Grahame Grieve (Jan 15 2020 at 20:36):

so, like, a FHIRException if the extension is not conformant?

view this post on Zulip Jens Villadsen (Jan 15 2020 at 20:40):

while extensions are first class citizens of the FHIR model, they are not totally first class citizens when interacting with the generic model

view this post on Zulip Grahame Grieve (Jan 15 2020 at 20:41):

that wasn't an answer...

view this post on Zulip Jens Villadsen (Jan 15 2020 at 20:42):

so, like, a FHIRException if the extension is not conformant?

depends on what you mean - eg. an extension not mentioned in the profile?

view this post on Zulip Grahame Grieve (Jan 15 2020 at 20:43):

an extension with a known type & cardinality where the instance being read has a different type or > max cardinality

view this post on Zulip Jens Villadsen (Jan 15 2020 at 20:46):

I imagine strictness to some extent could be made configurable ... - yet your case seems to 'breach the contract'

view this post on Zulip Jens Villadsen (Jan 15 2020 at 20:48):

you're entering hairy stuff once the model you receive differs from what you expect

view this post on Zulip Grahame Grieve (Jan 15 2020 at 20:48):

how could it be configurable?

  public int getCount() {
    getSingleExtension("http://acme.com/extension").getValueAsInteger().getValue();
  }

view this post on Zulip Grahame Grieve (Jan 15 2020 at 20:48):

you can't configure that into a different API to allow for anything unexpected, except to fall back to the existing methods

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:00):

correct

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:02):

not with that signature

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:03):

so:

  public int hasValidCount() {
    //...
  }

  public int getCount() throws FHIRException {
   //....
  }

  public JavaProfileClass setCount(int value) {
   //....
  }

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:05):

why the hasValidCount?

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:06):

so you can find out whether the underlying extension is valid without having to have an exception

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:06):

false if not present or not valid

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:06):

you could instead make it optional

public Optional<Integer> getCount()

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:07):

yes, you could, but then you always have to deal with that. just annoying, for me

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:09):

I guess all of it could go into the generated class

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:10):

all of what?

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:10):

all the above listed accessor methods

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:11):

what seems annoying to you may not seem annoying to me

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:11):

ok sure. could generate both, though they have to have different names

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:11):

sure

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:12):

the generation bootstrapping part could be configurable as well

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:12):

whether you want methods with optional signature or not

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:15):

of course, singleton extension facades are the simplest part of the problem. what about repeating extensions?

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:20):

as in multiple extensions (that also differ in type)?

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:27):

one extension that can repeat ... can have more than one value

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:36):

getExtensionsByUrl("").stream().map(e -> e.getValue()).map( cast it ...).collect(toList())

view this post on Zulip Grahame Grieve (Jan 15 2020 at 21:47):

what should the read and write API look like.

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:49):

getExtensionsByUrl("").stream().map(e -> e.getValue()).map( cast it ...).collect(toList())

that would be read

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:50):

unwrapped

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:52):

writing would be by adding collections or single elements

view this post on Zulip Jens Villadsen (Jan 15 2020 at 21:53):

backing datastore would be extensions

view this post on Zulip Grahame Grieve (Jan 15 2020 at 22:01):

but you really want to be able to enumerate.

view this post on Zulip Jens Villadsen (Jan 15 2020 at 22:03):

so a linked list would do the job, right?

view this post on Zulip Grahame Grieve (Jan 15 2020 at 22:27):

well, the choice is between 2 paradigms:

view this post on Zulip Grahame Grieve (Jan 15 2020 at 22:28):

  public List<CodeableConcept> getMode() {
  }

or

  public int getModeCount() {
  }

  public CodeableConcept getMode(int i) {
  }

view this post on Zulip Grahame Grieve (Jan 15 2020 at 22:29):

the first is more convenient, but the underlying list is not rooted onto the underlying extension list

view this post on Zulip Jens Villadsen (Jan 16 2020 at 08:13):

how come the first is not rooted to the underlying list?

view this post on Zulip Michel Jacobs (Jan 16 2020 at 11:02):

I have tried Java code generation from structure definitions with both the HAPI core class generator and Jens' generator.
Both didn’t really work (expected).
What we see is that the core generator does override all methods in all classes, and does not work for all R4 profile resources we have, and has no way to go back to an older version.
Jens’ generator does not handle anything else than (STU3) structure definitions and does not seem complete for STU3 (yet).

And for restarting the project, the generator isn’t the main goal of my internship. My focus is on generating FHIR test data compliant with (company or other) FHIR profiles.
For Synthea to generate profile compliant resource data, we need Java code for the profiled resources, which is ideally generated and not manually created of course.
But if we can get something working, we are willing to contribute to it.

view this post on Zulip Jens Villadsen (Jan 16 2020 at 12:17):

@Michel Jacobs - right, my generator is not complete. It was abandoned due to lack of time and no one else contributing to it

view this post on Zulip Jens Villadsen (Jan 16 2020 at 12:34):

@Michel Jacobs on another note - should you guys at Synthea need photos for your synthetic patients https://www.thispersondoesnotexist.com/


Last updated: Apr 12 2022 at 19:14 UTC