Stream: hapi
Topic: Class Generation for Profiles
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.
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.
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
Chris Moesel (Aug 22 2018 at 20:08):
Cool. I think that would be probably be useful to others as well!
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 ;)
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.
Chris Moesel (Aug 22 2018 at 20:12):
We actually kind of more-so need something like that in JavaScript.
Grahame Grieve (Aug 22 2018 at 21:59):
it's been my intention to produce something like this
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 ;)
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?
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
Jens Villadsen (Dec 13 2019 at 09:49):
@Sandro Zbinden
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?
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?
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.
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?
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.
Jens Villadsen (Jan 15 2020 at 17:42):
I agree
Jens Villadsen (Jan 15 2020 at 17:42):
It could be a way to discover changes in an IG
Jens Villadsen (Jan 15 2020 at 17:45):
So @Erik Moll / @Michel Jacobs should we restart this project of mine?
Grahame Grieve (Jan 15 2020 at 20:26):
I'm interested to know what your classes that represent profiles actually do
Jens Villadsen (Jan 15 2020 at 20:33):
There will be limitations of course - ... First thing would be ease of access to extension fields
Jens Villadsen (Jan 15 2020 at 20:34):
type safety
Grahame Grieve (Jan 15 2020 at 20:36):
so, like, a FHIRException if the extension is not conformant?
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
Grahame Grieve (Jan 15 2020 at 20:41):
that wasn't an answer...
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?
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
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'
Jens Villadsen (Jan 15 2020 at 20:48):
you're entering hairy stuff once the model you receive differs from what you expect
Grahame Grieve (Jan 15 2020 at 20:48):
how could it be configurable?
public int getCount() { getSingleExtension("http://acme.com/extension").getValueAsInteger().getValue(); }
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
Jens Villadsen (Jan 15 2020 at 21:00):
correct
Jens Villadsen (Jan 15 2020 at 21:02):
not with that signature
Grahame Grieve (Jan 15 2020 at 21:03):
so:
public int hasValidCount() { //... } public int getCount() throws FHIRException { //.... } public JavaProfileClass setCount(int value) { //.... }
Jens Villadsen (Jan 15 2020 at 21:05):
why the hasValidCount?
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
Grahame Grieve (Jan 15 2020 at 21:06):
false if not present or not valid
Jens Villadsen (Jan 15 2020 at 21:06):
you could instead make it optional
public Optional<Integer> getCount()
Grahame Grieve (Jan 15 2020 at 21:07):
yes, you could, but then you always have to deal with that. just annoying, for me
Jens Villadsen (Jan 15 2020 at 21:09):
I guess all of it could go into the generated class
Grahame Grieve (Jan 15 2020 at 21:10):
all of what?
Jens Villadsen (Jan 15 2020 at 21:10):
all the above listed accessor methods
Jens Villadsen (Jan 15 2020 at 21:11):
what seems annoying to you may not seem annoying to me
Grahame Grieve (Jan 15 2020 at 21:11):
ok sure. could generate both, though they have to have different names
Jens Villadsen (Jan 15 2020 at 21:11):
sure
Jens Villadsen (Jan 15 2020 at 21:12):
the generation bootstrapping part could be configurable as well
Jens Villadsen (Jan 15 2020 at 21:12):
whether you want methods with optional signature or not
Grahame Grieve (Jan 15 2020 at 21:15):
of course, singleton extension facades are the simplest part of the problem. what about repeating extensions?
Jens Villadsen (Jan 15 2020 at 21:20):
as in multiple extensions (that also differ in type)?
Grahame Grieve (Jan 15 2020 at 21:27):
one extension that can repeat ... can have more than one value
Jens Villadsen (Jan 15 2020 at 21:36):
getExtensionsByUrl("").stream().map(e -> e.getValue()).map( cast it ...).collect(toList())
Grahame Grieve (Jan 15 2020 at 21:47):
what should the read and write API look like.
Jens Villadsen (Jan 15 2020 at 21:49):
getExtensionsByUrl("").stream().map(e -> e.getValue()).map( cast it ...).collect(toList())
that would be read
Jens Villadsen (Jan 15 2020 at 21:50):
unwrapped
Jens Villadsen (Jan 15 2020 at 21:52):
writing would be by adding collections or single elements
Jens Villadsen (Jan 15 2020 at 21:53):
backing datastore would be extensions
Grahame Grieve (Jan 15 2020 at 22:01):
but you really want to be able to enumerate.
Jens Villadsen (Jan 15 2020 at 22:03):
so a linked list would do the job, right?
Grahame Grieve (Jan 15 2020 at 22:27):
well, the choice is between 2 paradigms:
Grahame Grieve (Jan 15 2020 at 22:28):
public List<CodeableConcept> getMode() { }
or
public int getModeCount() { } public CodeableConcept getMode(int i) { }
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
Jens Villadsen (Jan 16 2020 at 08:13):
how come the first is not rooted to the underlying list?
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.
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
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