Fix outstanding profile code generation issues

This commit is contained in:
Grahame Grieve 2024-11-26 11:48:29 +00:00
parent 8869698a48
commit 58581d5d95
6 changed files with 206 additions and 94 deletions

View File

@ -352,6 +352,7 @@ public class PEBuilder {
list = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
if (list.size() > 0) {
Set<String> names = new HashSet<>();
int i = 0;
while (i < list.size()) {
ElementDefinition defn = list.get(i);
@ -361,7 +362,8 @@ public class PEBuilder {
// DebugUtilities.breakpoint();
i++;
} else {
PEDefinitionElement pe = new PEDefinitionElement(this, profile, defn, parent.path());
String name = uniquefy(names, defn.getName());
PEDefinitionElement pe = new PEDefinitionElement(this, name, profile, defn, parent.path());
pe.setRecursing(definition == defn || (profile.getDerivation() == TypeDerivationRule.SPECIALIZATION && profile.getType().equals("Extension")));
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
pe.setMustHaveValue(definition.getMustHaveValue());
@ -376,14 +378,14 @@ public class PEBuilder {
while (i < list.size() && list.get(i).getPath().equals(defn.getPath())) {
StructureDefinition ext = getExtensionDefinition(list.get(i));
if (ext != null) {
res.add(new PEDefinitionExtension(this, list.get(i).getSliceName(), profile, list.get(i), defn, ext, parent.path()));
res.add(new PEDefinitionExtension(this, uniquefy(names, list.get(i).getSliceName()), profile, list.get(i), defn, ext, parent.path()));
} else if (isTypeSlicing(defn)) {
res.add(new PEDefinitionTypeSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
res.add(new PEDefinitionTypeSlice(this, uniquefy(names, list.get(i).getSliceName()), profile, list.get(i), defn, parent.path()));
} else {
if (ProfileUtilities.isComplexExtension(profile) && defn.getPath().endsWith(".extension")) {
res.add(new PEDefinitionSubExtension(this, profile, list.get(i), parent.path()));
} else {
res.add(new PEDefinitionSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
res.add(new PEDefinitionSlice(this, uniquefy(names, list.get(i).getSliceName()), profile, list.get(i), defn, parent.path()));
}
}
i++;
@ -409,6 +411,18 @@ public class PEBuilder {
}
}
private String uniquefy(Set<String> names, String name) {
if (names.contains(name)) {
int i = 0;
while (names.contains(name+i)) {
i++;
}
name = name+i;
}
names.add(name);
return name;
}
protected PEDefinition makeChild(PEDefinition parent, StructureDefinition profileStructure, ElementDefinition definition) {
PEDefinitionElement pe = new PEDefinitionElement(this, profileStructure, definition, parent.path());
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {

View File

@ -42,6 +42,10 @@ public class PEDefinitionElement extends PEDefinition {
super(builder, definition.getName(), profile, definition, ppath);
}
public PEDefinitionElement(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, String ppath) {
super(builder, name, profile, definition, ppath);
}
@Override
public void listTypes(List<PEType> types) {
for (TypeRefComponent t : definition.getType()) {

View File

@ -56,26 +56,26 @@ import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
/**
*
*
* The easiest way to generate code is to use the FHIR Validator, which can generate java classes for profiles
* using this code. Parameters:
*
*
* -codegen -version r4 -ig hl7.fhir.dk.core#3.2.0 -profiles http://hl7.dk/fhir/core/StructureDefinition/dk-core-gln-identifier,http://hl7.dk/fhir/core/StructureDefinition/dk-core-patient -output /Users/grahamegrieve/temp/codegen -package-name org.hl7.fhir.test
*
*
* Parameter Documentation:
* -codegen: tells the validator to generate code
* -version {r4|5}: which version to generate for
* -version {r4|5}: which version to generate for
* -ig {name}: loads an IG (and it's dependencies) - see -ig documentation for the validator
* -profiles {list}: a comma separated list of profile URLs to generate code for
* -profiles {list}: a comma separated list of profile URLs to generate code for
* -output {folder}: the folder where to generate the output java class source code
* -package-name {name}: the name of the java package to generate in
*
*
* options
* -option {name}: a code generation option, one of:
*
*
* narrative: generate code for the resource narrative (recommended: don't - leave that for the native resource level)
* meta: generate code the what's in meta
* contained: generate code for contained resources
* contained: generate code for contained resources
* all-elements: generate code for all elements, not just the key elements (makes the code verbose)
*/
@ -87,12 +87,12 @@ public class PECodeGenerator {
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(new Date());
}
public enum ExtensionPolicy {
None, Complexes, Primitives;
}
private class PEGenClass {
private String name;
private String base;
@ -101,7 +101,7 @@ public class PECodeGenerator {
private boolean isResource;
private Set<String> unfixed = new HashSet<>();
private Set<String> enumNames = new HashSet<>();
private StringBuilder inits = new StringBuilder();
private StringBuilder fields = new StringBuilder();
private StringBuilder enums = new StringBuilder();
@ -114,7 +114,7 @@ public class PECodeGenerator {
public void genId() {
if (isResource) {
genField(true, "id", "String", "id", "", false, "", 0, 1, null);
genAccessors(true, false, "id", "id", "String", "", "String", "String", "Id", "Ids", false, "", false, false, null);
genAccessors(true, false, "id", "id", "String", "", "String", "String", "Id", "Ids", false, "", false, false, null);
genLoad(true, false, "id", "id", "id", "IdType", "", "String", "String", "Id", "Ids", false, false, null, false);
genSave(true, false, "id", "id", "id", "IdType", "", "String", "String", "Id", "Ids", false, false, false, null, false);
genClear(false, "id", "String");
@ -128,14 +128,14 @@ public class PECodeGenerator {
w(b, " */");
w(b);
}
w(b, "// Generated by the HAPI Java Profile Generator, "+genDate);
w(b);
w(b, "// Generated by the HAPI Java Profile Generator, "+genDate);
w(b);
jdoc(b, doco, 0, true);
w(b, "public class "+name+" extends PEGeneratedBase {");
w(b);
if (url != null) {
w(b, " public static final String CANONICAL_URL = \""+url+"\";");
w(b);
w(b);
}
if (enums.length() > 0) {
w(b, enums.toString());
@ -172,7 +172,7 @@ public class PECodeGenerator {
w(b, " PEInstance src = builder.buildPEInstance(CANONICAL_URL, source);");
w(b, " theThing.load(src);");
w(b, " return theThing;");
w(b, " }");
w(b, " }");
w(b);
} else {
jdoc(b, "Used when loading other models ", 2, true);
@ -181,13 +181,13 @@ public class PECodeGenerator {
w(b, " theThing.workerContext = source.getContext();");
w(b, " theThing.load(source);");
w(b, " return theThing;");
w(b, " }");
w(b, " }");
}
w(b);
w(b, " public void load(PEInstance src) {");
w(b, " clear();");
w(b, load.toString());
w(b, " }");
w(b, " }");
w(b);
if (isResource) {
@ -201,7 +201,7 @@ public class PECodeGenerator {
w(b, " public "+base+" build() {");
w(b, " "+base+" theThing = new "+base+"();");
w(b, " PEBuilder builder = new PEBuilder(workerContext, PEElementPropertiesPolicy.EXTENSION, true);");
w(b, " PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, theThing);");
w(b, " PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, theThing);");
w(b, " save(tgt, false);");
w(b, " return theThing;");
w(b, " }");
@ -217,21 +217,21 @@ public class PECodeGenerator {
}
w(b, " public void save(PEInstance tgt, boolean nulls) {");
w(b, save.toString());
w(b, " }");
w(b, " }");
w(b);
if (inits.length() > 0) {
w(b, " private void initFixedValues() {");
w(b, inits.toString());
w(b, " }");
w(b, " }");
w(b);
}
w(b, accessors.toString());
w(b);
w(b, " public void clear() {");
w(b, clear.toString());
w(b, " }");
w(b, " }");
w(b);
w(b, "}");
w(b, "}");
}
private String generateEnum(PEDefinition source, PEDefinition field) {
@ -241,9 +241,14 @@ public class PECodeGenerator {
org.hl7.fhir.r4.model.ValueSet vs = workerContext.fetchResource(org.hl7.fhir.r4.model.ValueSet.class, binding.getValueSet());
if (vs != null) {
ValueSetExpansionOutcome vse = workerContext.expandVS(vs, false, false);
Set<String> codes = new HashSet<>();
boolean hasDups = false;
if (vse.isOk()) {
String baseName = Utilities.nmtokenize(Utilities.singularise(vs.getName()));
String name = baseName;
if (workerContext.getResourceNames().contains(name)) {
name = name+"Type";
}
int c = 0;
while (enumNames.contains(name)) {
c++;
@ -253,26 +258,40 @@ public class PECodeGenerator {
for (int i = 0; i < vse.getValueset().getExpansion().getContains().size(); i++) {
ValueSetExpansionContainsComponent cc = vse.getValueset().getExpansion().getContains().get(i);
String code = Utilities.javaTokenize(cc.getCode(), true).toUpperCase();
if (Utilities.isInteger(code)) {
code = "C_"+code;
}
if (cc.getAbstract()) {
code = "_"+code;
}
if (codes.contains(code)) {
char sfx = 'A';
while (codes.contains(code+sfx)) {
sfx++;
}
code = code + sfx;
hasDups = true;
}
codes.add(code);
cc.setUserData("java.code", code);
w(enums, " "+code+(i < vse.getValueset().getExpansion().getContains().size() - 1 ? "," : ";")+" // \""+cc.getDisplay()+"\" = "+cc.getSystem()+"#"+cc.getCode());
}
w(enums, "");
w(enums, " public static "+name+" fromCode(String s) {");
w(enums, " switch (s) {");
for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) {
w(enums, " case \""+cc.getCode()+"\": return "+cc.getUserString("java.code")+";");
if (!hasDups) {
w(enums, " public static "+name+" fromCode(String s) {");
w(enums, " switch (s) {");
for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) {
w(enums, " case \""+cc.getCode()+"\": return "+cc.getUserString("java.code")+";");
}
w(enums, " default: return null;");
w(enums, " }");
w(enums, " }");
w(enums, "");
}
w(enums, " default: return null;");
w(enums, " }");
w(enums, " }");
w(enums, "");
w(enums, " public static "+name+" fromCoding(Coding c) {");
for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) {
if (cc.hasVersion()) {
w(enums, " if (\""+cc.getSystem()+"\".equals(c.getSystem()) && \""+cc.getCode()+"\".equals(c.getCode()) && (!c.hasVersion() || \""+cc.getVersion()+"\".equals(c.getVersion()))) {");
w(enums, " if (\""+cc.getSystem()+"\".equals(c.getSystem()) && \""+cc.getCode()+"\".equals(c.getCode()) && (!c.hasVersion() || \""+cc.getVersion()+"\".equals(c.getVersion()))) {");
} else {
w(enums, " if (\""+cc.getSystem()+"\".equals(c.getSystem()) && \""+cc.getCode()+"\".equals(c.getCode())) {");
}
@ -302,16 +321,18 @@ public class PECodeGenerator {
w(enums, " }");
w(enums, " }");
w(enums, "");
w(enums, " public String toCode() {");
w(enums, " switch (this) {");
for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) {
w(enums, " case "+cc.getUserString("java.code")+": return \""+cc.getCode()+"\";");
if (!hasDups) {
w(enums, " public String toCode() {");
w(enums, " switch (this) {");
for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) {
w(enums, " case "+cc.getUserString("java.code")+": return \""+cc.getCode()+"\";");
}
w(enums, " default: return null;");
w(enums, " }");
w(enums, " }");
w(enums, "");
}
w(enums, " default: return null;");
w(enums, " }");
w(enums, " }");
w(enums, "");
w(enums, " public Coding toCoding() {");
w(enums, " switch (this) {");
for (ValueSetExpansionContainsComponent cc : vse.getValueset().getExpansion().getContains()) {
@ -337,6 +358,7 @@ public class PECodeGenerator {
}
return null;
}
private void defineField(PEDefinition source, PEDefinition field) {
if (field.types().size() == 1) {
StructureDefinition sd = workerContext.fetchTypeDefinition(field.types().get(0).getUrl());
@ -377,8 +399,8 @@ public class PECodeGenerator {
if (isPrim && field.hasFixedValue()) {
genFixed(name, ptype, field.getFixedValue());
}
genAccessors(isPrim, isAbstract, name, field.name(), type, init, ptype, ltype, cname, csname, field.isList(), field.documentation(), field.hasFixedValue(), isEnum, field.definition());
genLoad(isPrim, isAbstract, name, sname, field.name(), type, init, ptype, ltype, cname, csname, field.isList(), field.hasFixedValue(), field.types().get(0), isEnum);
genAccessors(isPrim, isAbstract, name, field.name(), type, init, ptype, ltype, cname, csname, field.isList(), field.documentation(), field.hasFixedValue(), isEnum, field.definition());
genLoad(isPrim, isAbstract, name, sname, field.name(), type, init, ptype, ltype, cname, csname, field.isList(), field.hasFixedValue(), field.types().get(0), isEnum);
genSave(isPrim, isAbstract, name, sname, field.name(), type, init, ptype, ltype, cname, csname, field.isList(), field.hasFixedValue(), isExtension, field.types().get(0), isEnum);
genClear(field.isList(), name, ptype);
}
@ -386,10 +408,10 @@ public class PECodeGenerator {
// ignoring polymorphics for now
}
}
private void genClear(boolean list, String name, String ptype) {
if (list) {
w(clear, " "+name+".clear();");
w(clear, " "+name+".clear();");
} else if ("boolean".equals(ptype)) {
w(clear, " "+name+" = false;");
} else if ("int".equals(ptype)) {
@ -398,16 +420,25 @@ public class PECodeGenerator {
w(clear, " "+name+" = null;");
}
}
private void genLoad(boolean isPrim, boolean isAbstract, String name, String sname, String fname, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, boolean isFixed, PEType typeInfo, boolean isEnum) {
if (isList) {
w(load, " for (PEInstance item : src.children(\""+fname+"\")) {");
if ("BackboneElement".equals(type)) {
w(load, " "+name+".add(("+type+") item.asElement());");
} else if (!Strings.isNullOrEmpty(typeInfo.getUrl()) && typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(load, " "+name+".add(("+type+") item.asDataType());");
if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(load, " "+name+".add("+type+".fromSource(src.child(\""+fname+"\")));");
} else if ("BackboneElement".equals(type)) {
w(load, " "+name+".add(("+type+") item.asElement());");
} else if (isEnum) {
if ("CodeableConcept".equals(typeInfo.getName())) {
w(load, " "+name+".add("+type+".fromCodeableConcept((CodeableConcept) item.asDataType()));");
} else if ("Coding".equals(typeInfo.getName())) {
w(load, " "+name+".add("+type+".fromCoding((Coding) item.asDataType()));");
} else {
w(load, " "+name+".add("+type+".fromCode(item.asDataType().primitiveValue()));");
}
} else {
w(load, " "+name+".add("+type+".fromSource(item));");
w(load, " "+name+".add(("+type+") item.asDataType());");
}
w(load, " }");
} else if (isEnum) {
@ -418,23 +449,23 @@ public class PECodeGenerator {
w(load, " "+name+" = "+type+".fromCoding((Coding) src.child(\""+fname+"\").asDataType());");
} else {
w(load, " "+name+" = "+type+".fromCode(src.child(\""+fname+"\").asDataType().primitiveValue());");
}
w(load, " }");
}
w(load, " }");
} else if (isPrim) {
w(load, " if (src.hasChild(\""+fname+"\")) {");
if ("CodeType".equals(type)) {
// might be code or enum
// might be code or enum
w(load, " "+name+" = src.child(\""+fname+"\").asDataType().primitiveValue();");
} else {
w(load, " "+name+" = (("+type+") src.child(\""+fname+"\").asDataType()).getValue();");
}
w(load, " }");
w(load, " }");
} else if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(load, " if (src.hasChild(\""+fname+"\")) {");
w(load, " "+name+" = "+type+".fromSource(src.child(\""+fname+"\"));");
w(load, " }");
} else {
w(load, " if (src.hasChild(\""+fname+"\")) {");
w(load, " if (src.hasChild(\""+fname+"\")) {");
if ("BackboneElement".equals(type)) {
w(load, " "+name+" = ("+type+") src.child(\""+fname+"\").asElement();");
} else if (Utilities.existsInList(type, workerContext.getResourceNames())) {
@ -450,10 +481,20 @@ public class PECodeGenerator {
w(save, " tgt.clear(\""+fname+"\");");
if (isList) {
w(save, " for ("+type+" item : "+name+") {");
if (isExtension && !Strings.isNullOrEmpty(typeInfo.getUrl()) && typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value[x]\", item);");
} else if (isExtension) {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value[x]\", item.getData());");
if (isExtension) {
if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(save, " item.save(tgt.makeChild(\""+fname+"\"), false);");
} else {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value[x]\", item);");
}
} else if (isEnum) {
if ("CodeableConcept".equals(typeInfo.getName())) {
w(save, " tgt.addChild(\""+fname+"\", item.toCodeableConcept());");
} else if ("Coding".equals(typeInfo.getName())) {
w(save, " tgt.addChild(\""+fname+"\", item.toCoding());");
} else {
w(save, " tgt.addChild(\""+fname+"\", item.toCode());");
}
} else {
w(save, " tgt.addChild(\""+fname+"\", item);");
}
@ -466,8 +507,8 @@ public class PECodeGenerator {
w(save, " tgt.addChild(\""+fname+"\", "+name+".toCoding());");
} else {
w(save, " tgt.addChild(\""+fname+"\", "+name+".toCode());");
}
w(save, " }");
}
w(save, " }");
} else if (isPrim) {
if ("boolean".equals(ptype)) {
w(save, " if (true) { // for now, at least");
@ -479,7 +520,7 @@ public class PECodeGenerator {
if (isExtension) {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value[x]\", new "+type+"("+name+"));");
} else if (Utilities.existsInList(type, "DateType", "InstantType", "DateTimeType")) {
w(save, " tgt.addChild(\""+fname+"\", new "+type+"("+name+"));");
w(save, " tgt.addChild(\""+fname+"\", new "+type+"("+name+"));");
} else {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value\", new "+type+"("+name+"));");
}
@ -511,7 +552,7 @@ public class PECodeGenerator {
if (isFixed) {
w(accessors, " public boolean has"+cname+"() {");
w(accessors, " return true;");
w(accessors, " }");
w(accessors, " }");
} else {
w(accessors, " public "+this.name+" set"+cname+"("+ptype+" value) {");
w(accessors, " this."+name+" = value;");
@ -520,13 +561,13 @@ public class PECodeGenerator {
w(accessors);
w(accessors, " public boolean has"+cname+"() {");
if ("boolean".equals(ptype)) {
w(accessors, " return true; // not "+name+" != false ?");
w(accessors, " return true; // not "+name+" != false ?");
} else if ("int".equals(ptype)) {
w(accessors, " return "+name+" != 0;");
w(accessors, " return "+name+" != 0;");
} else {
w(accessors, " return "+name+" != null;");
}
w(accessors, " }");
w(accessors, " }");
}
} else {
if (isPrim && !isList) {
@ -553,24 +594,24 @@ public class PECodeGenerator {
w(accessors, " return "+name+" != null && !"+name+".isEmpty();");
w(accessors, " }");
w(accessors);
if (!isAbstract) {
if (!isAbstract && !isEnum) {
w(accessors, " public "+type+" add"+csname+"() {");
w(accessors, " "+type+" theThing = new "+type+"();");
w(accessors, " get"+cname+"().add(theThing);");
w(accessors, " return theThing;");
w(accessors, " }");
w(accessors);
w(accessors);
}
w(accessors, " public boolean has"+csname+"("+type+" item) {");
w(accessors, " return has"+cname+"() && "+name+".contains(item);");
w(accessors, " }");
w(accessors);
w(accessors);
w(accessors, " public void remove"+csname+"("+type+" item) {");
w(accessors, " if (has"+csname+"(item)) {");
w(accessors, " "+name+".remove(item);");
w(accessors, " }");
w(accessors, " }");
w(accessors);
w(accessors);
} else if (isPrim) {
if (!isFixed) {
w(accessors, " public "+this.name+" set"+cname+"("+ptype+" value) {");
@ -586,7 +627,7 @@ public class PECodeGenerator {
w(accessors, " public boolean has"+cname+"() {");
w(accessors, " return "+name+" != null && "+name+".hasValue();");
w(accessors, " }");
w(accessors);
w(accessors);
} else {
if (!isFixed) {
w(accessors, " public "+this.name+" set"+cname+"("+type+" value) {");
@ -610,7 +651,7 @@ public class PECodeGenerator {
w(fields, " @BindingStrength(\""+ed.getBinding().getStrength().toCode()+"\") @ValueSet(\""+ed.getBinding().getValueSet()+"\")");
}
if (ed.getMustSupport()) {
w(fields, " @MustSupport(true)");
w(fields, " @MustSupport(true)");
}
if (ed.hasLabel() || ed.hasDefinition()) {
String s = "";
@ -620,7 +661,7 @@ public class PECodeGenerator {
if (ed.hasDefinition()) {
s = s + " @Definition(\""+Utilities.escapeJava(ed.getDefinition())+"\")";
}
w(fields, " "+s);
w(fields, " "+s);
}
}
if (isPrim && extensionPolicy != ExtensionPolicy.Primitives && !isList) {
@ -628,7 +669,7 @@ public class PECodeGenerator {
} else if (isList) {
w(fields, " private "+ltype+" "+name+" = new ArrayList<>();"+nn+" // "+shortDoco);
} else {
w(fields, " private "+ltype+" "+name+";"+nn+" // "+shortDoco);
w(fields, " private "+ltype+" "+name+";"+nn+" // "+shortDoco);
}
w(fields, "");
}
@ -768,8 +809,9 @@ public class PECodeGenerator {
PEDefinition source = new PEBuilder(workerContext, PEElementPropertiesPolicy.EXTENSION, true).buildPEDefinition(canonical);
w(imports, "import java.util.List;");
w(imports, "import java.util.ArrayList;");
w(imports, "import javax.annotation.Nullable;");
w(imports, "import java.util.Date;\r\n");
w(imports, "import java.math.BigDecimal;");
w(imports, "import javax.annotation.Nullable;");
w(imports);
w(imports, "import org.hl7.fhir."+version+".context.IWorkerContext;");
w(imports, "import org.hl7.fhir."+version+".model.*;");
@ -785,7 +827,7 @@ public class PECodeGenerator {
w(imports, "import org.hl7.fhir."+version+".profilemodel.gen.ValueSet;");
w(imports, "import org.hl7.fhir."+version+".profilemodel.gen.MustSupport;");
w(imports, "import org.hl7.fhir."+version+".profilemodel.gen.Definition;");
PEGenClass cls = genClass(source);
StringBuilder b = new StringBuilder();
@ -810,7 +852,7 @@ public class PECodeGenerator {
w(b, pfx+" *");
}
w(b, pfx+" */");
}
}
}
private List<String> naturalLines(String line) {
@ -839,7 +881,7 @@ public class PECodeGenerator {
private void w(StringBuilder b, String line) {
b.append(line);
w(b);
w(b);
}
private PEGenClass genClass(PEDefinition source) {
@ -854,7 +896,7 @@ public class PECodeGenerator {
if (genForField(source, child)) {
cls.defineField(source, child);
}
}
}
return cls;
}

View File

@ -29,7 +29,9 @@ package org.hl7.fhir.r5.profilemodel;
*/
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException;
@ -352,6 +354,7 @@ public class PEBuilder {
list = pu.getChildList(profile, profile.getSnapshot().getElementFirstRep());
}
if (list.size() > 0) {
Set<String> names = new HashSet<>();
int i = 0;
while (i < list.size()) {
ElementDefinition defn = list.get(i);
@ -361,7 +364,8 @@ public class PEBuilder {
// DebugUtilities.breakpoint();
i++;
} else {
PEDefinitionElement pe = new PEDefinitionElement(this, profile, defn, parent.path());
String name = uniquefy(names, defn.getName());
PEDefinitionElement pe = new PEDefinitionElement(this, name, profile, defn, parent.path());
pe.setRecursing(definition == defn || (profile.getDerivation() == TypeDerivationRule.SPECIALIZATION && profile.getType().equals("Extension")));
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {
pe.setMustHaveValue(definition.getMustHaveValue());
@ -376,14 +380,14 @@ public class PEBuilder {
while (i < list.size() && list.get(i).getPath().equals(defn.getPath())) {
StructureDefinition ext = getExtensionDefinition(list.get(i));
if (ext != null) {
res.add(new PEDefinitionExtension(this, list.get(i).getSliceName(), profile, list.get(i), defn, ext, parent.path()));
res.add(new PEDefinitionExtension(this, uniquefy(names, list.get(i).getSliceName()), profile, list.get(i), defn, ext, parent.path()));
} else if (isTypeSlicing(defn)) {
res.add(new PEDefinitionTypeSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
res.add(new PEDefinitionTypeSlice(this, uniquefy(names, list.get(i).getSliceName()), profile, list.get(i), defn, parent.path()));
} else {
if (ProfileUtilities.isComplexExtension(profile) && defn.getPath().endsWith(".extension")) {
res.add(new PEDefinitionSubExtension(this, profile, list.get(i), parent.path()));
} else {
res.add(new PEDefinitionSlice(this, list.get(i).getSliceName(), profile, list.get(i), defn, parent.path()));
res.add(new PEDefinitionSlice(this, uniquefy(names, list.get(i).getSliceName()), profile, list.get(i), defn, parent.path()));
}
}
i++;
@ -409,6 +413,18 @@ public class PEBuilder {
}
}
private String uniquefy(Set<String> names, String name) {
if (names.contains(name)) {
int i = 0;
while (names.contains(name+i)) {
i++;
}
name = name+i;
}
names.add(name);
return name;
}
protected PEDefinition makeChild(PEDefinition parent, StructureDefinition profileStructure, ElementDefinition definition) {
PEDefinitionElement pe = new PEDefinitionElement(this, profileStructure, definition, parent.path());
if (context.isPrimitiveType(definition.getTypeFirstRep().getWorkingCode()) && "value".equals(pe.name())) {

View File

@ -42,6 +42,10 @@ public class PEDefinitionElement extends PEDefinition {
super(builder, definition.getName(), profile, definition, ppath);
}
public PEDefinitionElement(PEBuilder builder, String name, StructureDefinition profile, ElementDefinition definition, String ppath) {
super(builder, name, profile, definition, ppath);
}
@Override
public void listTypes(List<PEType> types) {
for (TypeRefComponent t : definition.getType()) {

View File

@ -58,6 +58,7 @@ import org.hl7.fhir.r5.profilemodel.PEDefinition;
import org.hl7.fhir.r5.profilemodel.PEInstance;
import org.hl7.fhir.r5.profilemodel.PEType;
import org.hl7.fhir.utilities.CommaSeparatedStringBuilder;
import org.hl7.fhir.utilities.DebugUtilities;
import org.hl7.fhir.utilities.TextFile;
import org.hl7.fhir.utilities.Utilities;
@ -252,6 +253,9 @@ public class PECodeGenerator {
if (vse.isOk()) {
String baseName = Utilities.nmtokenize(Utilities.singularise(vs.getName()));
String name = baseName;
if (workerContext.getResourceNames().contains(name)) {
name = name+"Type";
}
int c = 0;
while (enumNames.contains(name)) {
c++;
@ -427,8 +431,19 @@ public class PECodeGenerator {
private void genLoad(boolean isPrim, boolean isAbstract, String name, String sname, String fname, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, boolean isFixed, PEType typeInfo, boolean isEnum) {
if (isList) {
w(load, " for (PEInstance item : src.children(\""+fname+"\")) {");
if ("BackboneElement".equals(type)) {
if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(load, " "+name+".add("+type+".fromSource(src.child(\""+fname+"\")));");
} else if ("BackboneElement".equals(type)) {
w(load, " "+name+".add(("+type+") item.asElement());");
} else if (isEnum) {
if ("CodeableConcept".equals(typeInfo.getName())) {
w(load, " "+name+".add("+type+".fromCodeableConcept((CodeableConcept) item.asDataType()));");
} else if ("Coding".equals(typeInfo.getName())) {
w(load, " "+name+".add("+type+".fromCoding((Coding) item.asDataType()));");
} else {
w(load, " "+name+".add("+type+".fromCode(item.asDataType().primitiveValue()));");
}
} else {
w(load, " "+name+".add(("+type+") item.asDataType());");
}
@ -474,7 +489,19 @@ public class PECodeGenerator {
if (isList) {
w(save, " for ("+type+" item : "+name+") {");
if (isExtension) {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value[x]\", item);");
if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
w(save, " item.save(tgt.makeChild(\""+fname+"\"), false);");
} else {
w(save, " tgt.makeChild(\""+fname+"\").data().setProperty(\"value[x]\", item);");
}
} else if (isEnum) {
if ("CodeableConcept".equals(typeInfo.getName())) {
w(save, " tgt.addChild(\""+fname+"\", item.toCodeableConcept());");
} else if ("Coding".equals(typeInfo.getName())) {
w(save, " tgt.addChild(\""+fname+"\", item.toCoding());");
} else {
w(save, " tgt.addChild(\""+fname+"\", item.toCode());");
}
} else {
w(save, " tgt.addChild(\""+fname+"\", item);");
}
@ -574,7 +601,7 @@ public class PECodeGenerator {
w(accessors, " return "+name+" != null && !"+name+".isEmpty();");
w(accessors, " }");
w(accessors);
if (!isAbstract) {
if (!isAbstract && !isEnum) {
w(accessors, " public "+type+" add"+csname+"() {");
w(accessors, " "+type+" theThing = new "+type+"();");
w(accessors, " get"+cname+"().add(theThing);");
@ -786,11 +813,16 @@ public class PECodeGenerator {
public String execute() throws IOException {
imports = new StringBuilder();
if ("http://ehealth.sundhed.dk/fhir/StructureDefinition/ehealth-appointment".equals(canonical)) {
DebugUtilities.breakpoint();
}
PEDefinition source = new PEBuilder(workerContext, PEElementPropertiesPolicy.EXTENSION, true).buildPEDefinition(canonical);
w(imports, "import java.util.List;");
w(imports, "import java.util.ArrayList;");
w(imports, "import javax.annotation.Nullable;");
w(imports, "import java.util.Date;\r\n");
w(imports, "import java.math.BigDecimal;");
w(imports, "import javax.annotation.Nullable;");
w(imports);
w(imports, "import org.hl7.fhir."+version+".context.IWorkerContext;");
w(imports, "import org.hl7.fhir."+version+".model.*;");
@ -807,7 +839,7 @@ public class PECodeGenerator {
w(imports, "import org.hl7.fhir."+version+".profilemodel.gen.MustSupport;");
w(imports, "import org.hl7.fhir."+version+".profilemodel.gen.Definition;");
PEGenClass cls = genClass(source);
StringBuilder b = new StringBuilder();
w(b, "package "+pkgName+";");