diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java
index 4dd63fd30..16317f63b 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEBuilder.java
@@ -30,7 +30,7 @@ import org.hl7.fhir.utilities.Utilities;
* *** NOTE: This sub-system is still under development ***
*
* This subsystem takes a profile and creates a view of the profile that stitches
- * all the parts together, and presents it as a seemless tree. There's two views:
+ * all the parts together, and presents it as a seamless tree. There's two views:
*
* - definition: A logical view of the contents of the profile
* - instance: a logical view of a resource that conforms to the profile
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java
index c38afca20..970a8056a 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEDefinition.java
@@ -294,6 +294,26 @@ public abstract class PEDefinition {
return !"1".equals(definition.getBase().getMax());
}
+
+ public StructureDefinition getProfile() {
+ return profile;
+ }
+
+
+ public boolean isKeyElement() {
+ boolean selfKey = definition.getMustSupport() || definition.getMustHaveValue() || min() > 0 || definition.hasCondition();
+ if (isProfiled() && !selfKey) {
+ if (types() != null && types().size() > 0) {
+ for (PEDefinition child : children()) {
+ if (child.isKeyElement()) {
+ return true;
+ }
+ }
+ }
+ }
+ return selfKey;
+ }
+
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java
index 184e49c53..650a1535e 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/PEInstance.java
@@ -13,6 +13,7 @@ import org.hl7.fhir.r5.model.Identifier;
import org.hl7.fhir.r5.model.DataType;
import org.hl7.fhir.r5.model.DateTimeType;
import org.hl7.fhir.r5.model.HumanName;
+import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Address;
import org.hl7.fhir.r5.model.PrimitiveType;
import org.hl7.fhir.r5.model.Quantity;
@@ -240,4 +241,14 @@ public class PEInstance {
public Base getBase() {
return data;
}
+
+ public boolean hasChild(String name) {
+ PEDefinition child = byName(definition.children(), name);
+ List instances = builder.exec(resource, data, child.fhirpath());
+ return !instances.isEmpty();
+ }
+
+ public IWorkerContext getContext() {
+ return builder.getContext();
+ }
}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java
new file mode 100644
index 000000000..70f1f6aa4
--- /dev/null
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PECodeGenerator.java
@@ -0,0 +1,549 @@
+package org.hl7.fhir.r5.profilemodel.gen;
+
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Locale;
+import java.util.ArrayList;
+import java.util.Date;
+
+import org.hl7.fhir.r5.context.IWorkerContext;
+import org.hl7.fhir.r5.model.CodeableConcept;
+import org.hl7.fhir.r5.model.Identifier;
+import org.hl7.fhir.r5.model.Observation;
+import org.hl7.fhir.r5.model.StructureDefinition;
+import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
+import org.hl7.fhir.r5.profilemodel.PEBuilder;
+import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
+import org.hl7.fhir.r5.profilemodel.gen.PECodeGenerator.ExtensionPolicy;
+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.TextFile;
+import org.hl7.fhir.utilities.Utilities;
+
+public class PECodeGenerator {
+
+ public enum ExtensionPolicy {
+ None, Complexes, Primitives;
+ }
+ public static final SimpleDateFormat DATE_FORMAT() {
+ return new SimpleDateFormat("EEE, MMM d, yyyy HH:mmZ", new Locale("en", "US"));
+ }
+ private class PEGenClass {
+ private String name;
+ private String base;
+ private String doco;
+ private String url;
+ private boolean isResource;
+ private StringBuilder fields = new StringBuilder();
+ private StringBuilder load = new StringBuilder();
+ private StringBuilder save = new StringBuilder();
+ private StringBuilder clear = new StringBuilder();
+ private StringBuilder copy = new StringBuilder();
+ private StringBuilder accessors = new StringBuilder();
+ private StringBuilder hash = new StringBuilder();
+
+ public void genId() {
+ if (isResource) {
+ genField(true, "id", "String", "id", "", false, "");
+ genAccessors(true, false, "id", "String", "", "String", "String", "Id", "Ids", false, "", false);
+ genLoad(true, false, "id", "IdType", "", "String", "String", "Id", "Ids", false, false, null);
+ genClear(false, "id");
+ }
+ }
+ public void write(StringBuilder b) {
+ w(b);
+ w(b, "// Generated by the HAPI Java Profile Generator, "+DATE_FORMAT().format(new Date()));
+ w(b);
+ jdoc(b, doco, 0, true);
+ w(b, "public class "+name+" extends PEGeneratedBase {");
+ w(b);
+ if (url != null) {
+ w(b, " private static final String CANONICAL_URL = \""+url+"\";");
+ w(b);
+ }
+ w(b, fields.toString());
+ jdoc(b, "Parameter-less constructor. If you use this, the fixed values won't be filled out - they'll be missing. They'll be filled in if/when you call build, so they won't be missing from the resource, only from this particular object model", 2, true);
+ w(b, " public "+name+"() {");
+ w(b, " // todo");
+ w(b, " }");
+ w(b);
+ if (isResource) {
+ jdoc(b, "Construct an instance of the object, and fill out all the fixed values ", 2, true);
+ w(b, " public "+name+"(IWorkerContext context) {");
+ w(b, " workerContext = context;");
+ w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
+ w(b, " PEInstance src = builder.buildPEInstance(CANONICAL_URL, builder.createResource(CANONICAL_URL, false));");
+ w(b, " load(src);");
+ w(b, " }");
+ w(b);
+ jdoc(b, "Populate an instance of the object based on this source object ", 2, true);
+ w(b, " public static "+name+" fromSource(IWorkerContext context, "+base+" source) {");
+ w(b, " "+name+" theThing = new "+name+"();");
+ w(b, " theThing.workerContext = context;");
+ w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
+ w(b, " PEInstance src = builder.buildPEInstance(CANONICAL_URL, source);");
+ w(b, " theThing.load(src);");
+ w(b, " return theThing;");
+ w(b, " }");
+ w(b);
+ } else {
+ jdoc(b, "Used when loading other models ", 2, true);
+ w(b, " public static "+name+" fromSource(PEInstance source) {");
+ w(b, " "+name+" theThing = new "+name+"();");
+ w(b, " theThing.workerContext = source.getContext();");
+ w(b, " theThing.load(source);");
+ w(b, " return theThing;");
+ w(b, " }");
+ }
+ w(b);
+ w(b, " public void load(PEInstance src) {");
+ w(b, " clear();");
+ w(b, load.toString());
+ w(b, " }");
+ w(b);
+
+ if (isResource) {
+ jdoc(b, "Build an instance of the object based on this source object ", 2, true);
+ w(b, " public "+base+" build(IWorkerContext context) {");
+ w(b, " workerContext = context;");
+ w(b, " "+base+" theThing = new "+base+"();");
+ w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
+ w(b, " PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, theThing);");
+ w(b, " save(tgt, false);");
+ w(b, " return theThing;");
+ w(b, " }");
+ w(b);
+ jdoc(b, "Save this profile class into an existing resource (overwriting enything that exists in the profile) ", 2, true);
+ w(b, " public void save(IWorkerContext context, "+base+" dest, boolean nulls) {");
+ w(b, " workerContext = context;");
+ w(b, " PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);");
+ w(b, " PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, dest);");
+ w(b, " save(tgt, nulls);");
+ w(b, " }");
+ w(b);
+ }
+ w(b, " public void save(PEInstance tgt, boolean nulls) {");
+ w(b, save.toString());
+ 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, "}");
+ }
+
+ private void defineField(PEDefinition source, PEDefinition field) {
+ if (field.types().size() == 1) {
+ StructureDefinition sd = workerContext.fetchTypeDefinition(field.types().get(0).getUrl());
+ if (sd != null) {
+ boolean isPrim = sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE;
+ boolean isAbstract = sd.getAbstract();
+ String name = field.name().replace("[x]", "");
+ String sname = name;
+ String type = null;
+ String init = "";
+ String ptype = type;
+ if (isPrim) {
+ // todo: are we extension-less?
+ type = Utilities.capitalize(field.types().get(0).getName()+"Type");
+ ptype = getPrimitiveType(sd);
+ } else {
+ type = field.types().get(0).getName();
+ }
+ String ltype = type;
+ if (field.isList()) {
+ ltype = "List<"+type+">";
+ init = "new ArrayList<>()";
+ if (!Utilities.existsInList(name, "contained")) {
+ name = Utilities.pluralize(name, 2);
+ }
+ }
+ String cname = Utilities.capitalize(name);
+ String csname = Utilities.capitalize(sname);
+ String nn = field.min() == 1 ? "// @NotNull" : "";
+ genField(isPrim, name, ptype, ltype, nn, field.isList(), field.shortDocumentation());
+ genAccessors(isPrim, isAbstract, name, type, init, ptype, ltype, cname, csname, field.isList(), field.documentation(), field.fixedValue());
+ genLoad(isPrim, isAbstract, name, type, init, ptype, ltype, cname, csname, field.isList(), field.fixedValue(), field.types().get(0));
+ genClear(field.isList(), name);
+ }
+ } else {
+ // ignoring polymorphics for now
+ }
+
+ }
+
+ private void genClear(boolean list, String name) {
+ w(clear, " "+name+" = null;");
+ }
+ private void genLoad(boolean isPrim, boolean isAbstract, String name, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, boolean isFixed, PEType typeInfo) {
+ if (isList) {
+ w(load, " for (PEInstance item : src.children(\""+name+"\")) {");
+ w(load, " "+name+".add(("+type+") item.asDataType());");
+ w(load, " }");
+ } else if (isPrim) {
+ w(load, " if (src.hasChild(\""+name+"\")) {");
+ w(load, " "+name+" = (("+type+") src.child(\""+name+"\").asDataType()).getValue();");
+ w(load, " }");
+ } else if (typeInfo != null && typeInfo.getUrl() != null && !typeInfo.getUrl().startsWith("http://hl7.org/fhir/StructureDefinition")) {
+ w(load, " if (src.hasChild(\""+name+"\")) {");
+ w(load, " "+name+" = "+type+".fromSource(src.child(\""+name+"\"));");
+ w(load, " }");
+ } else {
+ w(load, " if (src.hasChild(\""+name+"\")) {");
+ w(load, " "+name+" = ("+type+") src.child(\""+name+"\").asDataType();");
+ w(load, " }");
+ }
+ }
+
+ private void genAccessors(boolean isPrim, boolean isAbstract, String name, String type, String init, String ptype, String ltype, String cname, String csname, boolean isList, String shortDoco, boolean isFixed) {
+ jdoc(accessors, doco, 2, true);
+ if (isPrim && extensionPolicy != ExtensionPolicy.Primitives && !isList) {
+ w(accessors, " public "+ptype+" get"+cname+"() {");
+ w(accessors, " return "+name+";");
+ w(accessors, " }");
+ w(accessors);
+ w(accessors, " public "+this.name+" set"+cname+"("+ptype+" value) {");
+ w(accessors, " this."+name+" = value;");
+ w(accessors, " return this;");
+ w(accessors, " }");
+ w(accessors);
+ w(accessors, " public boolean has"+cname+"() {");
+ w(accessors, " return "+name+" != null;");
+ w(accessors, " }");
+ } else {
+ if (isPrim && !isList) {
+ w(accessors, " public "+ptype+" get"+cname+"() {");
+ w(accessors, " if ("+name+" == null) { "+name+" = new "+type+"(); }");
+ w(accessors, " return "+name+".getValue();");
+ w(accessors, " }");
+ w(accessors, " public "+ltype+" get"+cname+"Element() {");
+ } else if (isAbstract && !isList) {
+ w(accessors, " public @Nullable "+ltype+" get"+cname+"() { // "+ltype+" is abstract ");
+ } else {
+ w(accessors, " public "+ltype+" get"+cname+"() {");
+ }
+ if (isList) {
+ w(accessors, " if ("+name+" == null) { "+name+" = "+init+"; }");
+ } else if (!isAbstract) {
+ w(accessors, " if ("+name+" == null) { "+name+" = new "+type+"(); }");
+ }
+ w(accessors, " return "+name+";");
+ w(accessors, " }");
+ w(accessors);
+ if (isList) {
+ w(accessors, " public boolean has"+cname+"() {");
+ w(accessors, " return "+name+" != null && !"+name+".isEmpty();");
+ w(accessors, " }");
+ w(accessors);
+ if (!isAbstract) {
+ 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, " public boolean has"+csname+"("+type+" item) {");
+ w(accessors, " return has"+cname+"() && "+name+".contains(item);");
+ 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);
+ } else if (isPrim) {
+ if (!isFixed) {
+ w(accessors, " public "+this.name+" set"+cname+"("+ptype+" value) {");
+ w(accessors, " if ("+name+" == null) { "+name+" = new "+type+"(); }");
+ w(accessors, " "+name+".setValue(value);");
+ w(accessors, " return this;");
+ w(accessors, " }");
+ w(accessors, " public "+this.name+" set"+cname+"Element("+type+" value) {");
+ w(accessors, " this."+name+" = value;");
+ w(accessors, " return this;");
+ w(accessors, " }");
+ }
+ w(accessors, " public boolean has"+cname+"() {");
+ w(accessors, " return "+name+" != null && "+name+".hasValue();");
+ w(accessors, " }");
+ w(accessors);
+ } else {
+ if (!isFixed) {
+ w(accessors, " public "+this.name+" set"+cname+"("+type+" value) {");
+ w(accessors, " this."+name+" = value;");
+ w(accessors, " return this;");
+ w(accessors, " }");
+ }
+ w(accessors, " public boolean has"+cname+"() {");
+ w(accessors, " return "+name+" != null;");
+ w(accessors, " }");
+ }
+ }
+ w(accessors);
+ }
+
+ private void genField(boolean isPrim, String name, String ptype, String ltype, String nn, boolean isList, String shortDoco) {
+ // jdoc(fields, field.documentation(), 2, true);
+ if (isPrim && extensionPolicy != ExtensionPolicy.Primitives && !isList) {
+ w(fields, " private "+ptype+" "+name+";"+nn+" // "+shortDoco);
+ } else {
+ w(fields, " private "+ltype+" "+name+";"+nn+" // "+shortDoco);
+ }
+ }
+ }
+
+ private String folder;
+ private IWorkerContext workerContext;
+ private String canonical;
+ private String pkgName;
+
+ // options:
+ private ExtensionPolicy extensionPolicy;
+ private boolean narrative;
+ private boolean contained;
+ private boolean meta;
+ private String language;
+ private boolean keyELementsOnly;
+
+ public PECodeGenerator(IWorkerContext workerContext) {
+ super();
+ this.workerContext = workerContext;
+ }
+
+ public String getFolder() {
+ return folder;
+ }
+
+
+ public void setFolder(String folder) {
+ this.folder = folder;
+ }
+
+
+ public String getCanonical() {
+ return canonical;
+ }
+
+ public void setCanonical(String canonical) {
+ this.canonical = canonical;
+ }
+
+
+ public String getPkgName() {
+ return pkgName;
+ }
+
+ public void setPkgName(String pkgName) {
+ this.pkgName = pkgName;
+ }
+
+ public ExtensionPolicy getExtensionPolicy() {
+ return extensionPolicy;
+ }
+
+ public void setExtensionPolicy(ExtensionPolicy extensionPolicy) {
+ this.extensionPolicy = extensionPolicy;
+ }
+
+ public boolean isNarrative() {
+ return narrative;
+ }
+
+ public void setNarrative(boolean narrative) {
+ this.narrative = narrative;
+ }
+
+ public boolean isMeta() {
+ return meta;
+ }
+
+ public void setMeta(boolean meta) {
+ this.meta = meta;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ public boolean isKeyELementsOnly() {
+ return keyELementsOnly;
+ }
+
+ public void setKeyELementsOnly(boolean keyELementsOnly) {
+ this.keyELementsOnly = keyELementsOnly;
+ }
+
+ public boolean isContained() {
+ return contained;
+ }
+
+ public void setContained(boolean contained) {
+ this.contained = contained;
+ }
+
+ private StringBuilder imports = new StringBuilder();
+
+ /**
+ * @throws IOException
+ *
+ */
+ public void execute() throws IOException {
+ 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);
+ w(imports, "import org.hl7.fhir.r5.context.IWorkerContext;");
+ w(imports, "import org.hl7.fhir.r5.model.*;");
+ w(imports, "import org.hl7.fhir.r5.profilemodel.PEBuilder;");
+ w(imports, "import org.hl7.fhir.r5.profilemodel.PEInstance;");
+ w(imports, "import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;");
+ w(imports, "import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase;");
+ PEGenClass cls = genClass(source);
+ StringBuilder b = new StringBuilder();
+ w(b, "package "+pkgName+";");
+ w(b);
+ if (source.getProfile().hasCopyright()) {
+ jdoc(b, source.getProfile().getCopyright(), 0, false);
+ }
+ w(b, imports.toString());
+ cls.write(b);
+ TextFile.stringToFile(b.toString(), Utilities.path(folder, cls.name+".java"));
+ }
+
+ public void jdoc(StringBuilder b, String doco, int indent, boolean jdoc) {
+ if (!Utilities.noString(doco)) {
+ String pfx = Utilities.padLeft("", ' ', indent);
+ w(b, pfx+"/*"+(jdoc ? "*" : ""));
+ for (String line : doco.split("\\R")) {
+ for (String nl : naturalLines(line))
+ w(b, pfx+" * "+nl);
+ w(b, pfx+" *");
+ }
+ w(b, pfx+" */");
+ }
+ }
+
+ private List naturalLines(String line) {
+ List lines = new ArrayList<>();
+ while (line.length() > 80) {
+ int cutpoint = 80;
+ while (cutpoint > 0 && line.charAt(cutpoint) != ' ') {
+ cutpoint--;
+ }
+ if (cutpoint == 0) {
+ cutpoint = 80;
+ } else {
+ cutpoint++;
+ }
+ lines.add(line.substring(0, cutpoint));
+ line = line.substring(cutpoint);
+ }
+ lines.add(line);
+ return lines;
+ }
+
+ private void w(StringBuilder b) {
+ b.append("\r\n");
+
+ }
+
+ private void w(StringBuilder b, String line) {
+ b.append(line);
+ w(b);
+ }
+
+ private PEGenClass genClass(PEDefinition source) {
+ PEGenClass cls = new PEGenClass();
+ cls.name = source.getProfile().getName();
+ cls.base = source.getProfile().getType();
+ cls.doco = source.documentation();
+ cls.url = source.getProfile().getVersionedUrl();
+ cls.isResource = source.getProfile().getKind() == StructureDefinitionKind.RESOURCE;
+ cls.genId();
+ for (PEDefinition child : source.children()) {
+ if (genForField(source, child)) {
+ cls.defineField(source, child);
+ }
+ }
+ return cls;
+ }
+
+ private boolean genForField(PEDefinition source, PEDefinition child) {
+ if (child.definition().getBase().getPath().equals("Resource.meta")) {
+ return meta;
+ }
+ if (child.definition().getBase().getPath().equals("DomainResource.text")) {
+ return narrative;
+ }
+ if (child.definition().getBase().getPath().equals("Resource.language")) {
+ return language == null;
+ }
+ if (child.definition().getBase().getPath().endsWith(".extension") || child.definition().getBase().getPath().endsWith(".modifierExtension")) {
+ return extensionPolicy == ExtensionPolicy.Complexes;
+ }
+ if (child.definition().getBase().getPath().equals("DomainResource.contained")) {
+ return contained;
+ }
+ return !keyELementsOnly || (child.isKeyElement());
+ }
+
+
+ private String getPrimitiveType(StructureDefinition sd) {
+
+ if (sd.getType().equals("string"))
+ return "String";
+ if (sd.getType().equals("code"))
+ return "String";
+ if (sd.getType().equals("markdown"))
+ return "String";
+ if (sd.getType().equals("base64Binary"))
+ return "byte[]";
+ if (sd.getType().equals("uri"))
+ return "String";
+ if (sd.getType().equals("url"))
+ return "String";
+ if (sd.getType().equals("canonical"))
+ return "String";
+ if (sd.getType().equals("oid"))
+ return "String";
+ if (sd.getType().equals("integer"))
+ return "int";
+ if (sd.getType().equals("integer64"))
+ return "long";
+ if (sd.getType().equals("unsignedInt"))
+ return "int";
+ if (sd.getType().equals("positiveInt"))
+ return "int";
+ if (sd.getType().equals("boolean"))
+ return "boolean";
+ if (sd.getType().equals("decimal"))
+ return "BigDecimal";
+ if (sd.getType().equals("dateTime"))
+ return "Date";
+ if (sd.getType().equals("date"))
+ return "Date";
+ if (sd.getType().equals("id"))
+ return "String";
+ if (sd.getType().equals("instant"))
+ return "Date";
+ if (sd.getType().equals("time"))
+ return "String";
+
+ return "??";
+ }
+
+}
diff --git a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java
index b36130735..f576261ab 100644
--- a/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java
+++ b/org.hl7.fhir.r5/src/main/java/org/hl7/fhir/r5/profilemodel/gen/PEGeneratedBase.java
@@ -1,12 +1,17 @@
package org.hl7.fhir.r5.profilemodel.gen;
+import org.hl7.fhir.r5.context.IWorkerContext;
import org.hl7.fhir.r5.model.Base;
import org.hl7.fhir.r5.profilemodel.PEInstance;
public class PEGeneratedBase {
+
+ protected IWorkerContext workerContext;
+ @Deprecated
protected PEInstance instance;
+ @Deprecated
protected void removeChild(String name) {
PEInstance child = instance.child(name);
if (child != null) {
@@ -14,16 +19,19 @@ public class PEGeneratedBase {
}
}
+ @Deprecated
protected void removeChildren(String name) {
for (PEInstance child : instance.children(name)) {
instance.removeChild(child);
}
}
+ @Deprecated
public PEInstance getInstance() {
return instance;
}
+ @Deprecated
public Base getData() {
return instance.getBase();
}
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java
index a4da8cd6a..a8d999ec6 100644
--- a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/PETests.java
@@ -1,5 +1,6 @@
package org.hl7.fhir.r5.profiles;
+import java.io.File;
import java.io.IOException;
import java.util.List;
@@ -13,6 +14,8 @@ import org.hl7.fhir.r5.model.Resource;
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.r5.profilemodel.gen.PECodeGenerator;
+import org.hl7.fhir.r5.profilemodel.gen.PECodeGenerator.ExtensionPolicy;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.LOINCCodesForCholesterolInSerumPlasma;
import org.hl7.fhir.r5.profilemodel.gen.ProfileExample.ProfileExampleComplex;
@@ -370,5 +373,22 @@ public class PETests {
Assertions.assertEquals("Another string value", sl3.getSlice3b().get(0).primitiveValue());
}
-
+
+ @Test
+ public void testGenerate() throws IOException {
+ load();
+ PECodeGenerator gen = new PECodeGenerator(ctxt);
+ gen.setFolder(Utilities.path("[tmp]"));
+ gen.setCanonical("http://hl7.org/fhir/test/StructureDefinition/pe-profile1");
+ gen.setPkgName("org.hl7.fhir.r5.profiles");
+ gen.setExtensionPolicy(ExtensionPolicy.None);
+ gen.setNarrative(false);
+ gen.setMeta(false);
+ gen.setLanguage("en-AU");
+ gen.setContained(false);
+ gen.setKeyELementsOnly(true);
+ gen.execute();
+ gen.setCanonical("http://hl7.org/fhir/test/StructureDefinition/pe-profile2");
+ gen.execute();
+ }
}
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestDatatypeProfile.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestDatatypeProfile.java
new file mode 100644
index 000000000..018dacfc5
--- /dev/null
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestDatatypeProfile.java
@@ -0,0 +1,203 @@
+package org.hl7.fhir.r5.profiles;
+
+import java.util.List;
+import java.util.ArrayList;
+import javax.annotation.Nullable;
+import java.util.Date;
+
+
+import org.hl7.fhir.r5.context.IWorkerContext;
+import org.hl7.fhir.r5.model.*;
+import org.hl7.fhir.r5.profilemodel.PEBuilder;
+import org.hl7.fhir.r5.profilemodel.PEInstance;
+import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
+import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase;
+import java.util.List;
+import java.util.ArrayList;
+import javax.annotation.Nullable;
+import java.util.Date;
+
+
+import org.hl7.fhir.r5.context.IWorkerContext;
+import org.hl7.fhir.r5.model.*;
+import org.hl7.fhir.r5.profilemodel.PEBuilder;
+import org.hl7.fhir.r5.profilemodel.PEInstance;
+import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
+import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase;
+
+
+// Generated by the HAPI Java Profile Generator, Sun, Aug 20, 2023 19:05+1000
+
+/**
+ * Test CodeableConcept Profile.
+ *
+ */
+public class TestDatatypeProfile extends PEGeneratedBase {
+
+ private static final String CANONICAL_URL = "http://hl7.org/fhir/test/StructureDefinition/pe-profile2|0.1";
+
+ private List codings;// @NotNull // Code defined by a terminology system
+ private List snomedcts;// @NotNull // Code defined by a terminology system
+ private List loincs; // Code defined by a terminology system
+ private String text;// @NotNull // Plain text representation of the concept
+
+ /**
+ * Parameter-less constructor. If you use this, the fixed values won't be filled
+ * out - they'll be missing. They'll be filled in if/when you call build, so they
+ * won't be missing from the resource, only from this particular object model
+ *
+ */
+ public TestDatatypeProfile() {
+ // todo
+ }
+
+ /**
+ * Used when loading other models
+ *
+ */
+ public static TestDatatypeProfile fromSource(PEInstance source) {
+ TestDatatypeProfile theThing = new TestDatatypeProfile();
+ theThing.workerContext = source.getContext();
+ theThing.load(source);
+ return theThing;
+ }
+
+ public void load(PEInstance src) {
+ clear();
+ for (PEInstance item : src.children("codings")) {
+ codings.add((Coding) item.asDataType());
+ }
+ for (PEInstance item : src.children("snomedcts")) {
+ snomedcts.add((Coding) item.asDataType());
+ }
+ for (PEInstance item : src.children("loincs")) {
+ loincs.add((Coding) item.asDataType());
+ }
+ if (src.hasChild("text")) {
+ text = ((StringType) src.child("text").asDataType()).getValue();
+ }
+
+ }
+
+ public void save(PEInstance tgt, boolean nulls) {
+
+ }
+
+ /**
+ * Test CodeableConcept Profile.
+ *
+ */
+ public List getCodings() {
+ if (codings == null) { codings = new ArrayList<>(); }
+ return codings;
+ }
+
+ public boolean hasCodings() {
+ return codings != null && !codings.isEmpty();
+ }
+
+ public Coding addCoding() {
+ Coding theThing = new Coding();
+ getCodings().add(theThing);
+ return theThing;
+ }
+
+ public boolean hasCoding(Coding item) {
+ return hasCodings() && codings.contains(item);
+ }
+
+ public void removeCoding(Coding item) {
+ if (hasCoding(item)) {
+ codings.remove(item);
+ }
+ }
+
+
+ /**
+ * Test CodeableConcept Profile.
+ *
+ */
+ public List getSnomedcts() {
+ if (snomedcts == null) { snomedcts = new ArrayList<>(); }
+ return snomedcts;
+ }
+
+ public boolean hasSnomedcts() {
+ return snomedcts != null && !snomedcts.isEmpty();
+ }
+
+ public Coding addSnomedct() {
+ Coding theThing = new Coding();
+ getSnomedcts().add(theThing);
+ return theThing;
+ }
+
+ public boolean hasSnomedct(Coding item) {
+ return hasSnomedcts() && snomedcts.contains(item);
+ }
+
+ public void removeSnomedct(Coding item) {
+ if (hasSnomedct(item)) {
+ snomedcts.remove(item);
+ }
+ }
+
+
+ /**
+ * Test CodeableConcept Profile.
+ *
+ */
+ public List getLoincs() {
+ if (loincs == null) { loincs = new ArrayList<>(); }
+ return loincs;
+ }
+
+ public boolean hasLoincs() {
+ return loincs != null && !loincs.isEmpty();
+ }
+
+ public Coding addLoinc() {
+ Coding theThing = new Coding();
+ getLoincs().add(theThing);
+ return theThing;
+ }
+
+ public boolean hasLoinc(Coding item) {
+ return hasLoincs() && loincs.contains(item);
+ }
+
+ public void removeLoinc(Coding item) {
+ if (hasLoinc(item)) {
+ loincs.remove(item);
+ }
+ }
+
+
+ /**
+ * Test CodeableConcept Profile.
+ *
+ */
+ public String getText() {
+ return text;
+ }
+
+ public TestDatatypeProfile setText(String value) {
+ this.text = value;
+ return this;
+ }
+
+ public boolean hasText() {
+ return text != null;
+ }
+
+
+
+ public void clear() {
+ codings = null;
+ snomedcts = null;
+ loincs = null;
+ text = null;
+
+ }
+
+}
diff --git a/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestProfile.java b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestProfile.java
new file mode 100644
index 000000000..47c0863a1
--- /dev/null
+++ b/org.hl7.fhir.r5/src/test/java/org/hl7/fhir/r5/profiles/TestProfile.java
@@ -0,0 +1,335 @@
+package org.hl7.fhir.r5.profiles;
+
+/*
+ * Licensed under CC0 1.0 Universal (CC0 1.0).
+ *
+ * The person who associated a work with this deed has dedicated the work to the
+ * public domain by waiving all of his or her rights to the work worldwide under
+ * copyright law, including all related and neighboring rights, to the extent
+ * allowed by law.
+ *
+ * You can copy, modify, distribute and perform the work, even for commercial
+ * purposes, all without asking permission. See Other Information below.
+ *
+ */
+import java.util.List;
+import java.util.ArrayList;
+import javax.annotation.Nullable;
+import java.util.Date;
+
+
+import org.hl7.fhir.r5.context.IWorkerContext;
+import org.hl7.fhir.r5.model.*;
+import org.hl7.fhir.r5.profilemodel.PEBuilder;
+import org.hl7.fhir.r5.profilemodel.PEInstance;
+import org.hl7.fhir.r5.profilemodel.PEBuilder.PEElementPropertiesPolicy;
+import org.hl7.fhir.r5.profilemodel.gen.PEGeneratedBase;
+
+
+// Generated by the HAPI Java Profile Generator, Sun, Aug 20, 2023 19:01+1000
+
+/**
+ * Test Observation Profile.
+ *
+ */
+public class TestProfile extends PEGeneratedBase {
+
+ private static final String CANONICAL_URL = "http://hl7.org/fhir/test/StructureDefinition/pe-profile1|0.1";
+
+ private String id; //
+ private List identifiers; // Business Identifier for observation
+ private String status;// @NotNull // registered | preliminary | final | amended +
+ private CodeableConcept code;// @NotNull // Sexual Orientation
+ private Reference subject;// @NotNull // Who and/or what the observation is about
+ private Reference encounter; // Healthcare event during which this observation is made
+ private Date effective;// @NotNull // Clinically relevant time/time-period for observation
+ private List performers; // Who is responsible for the observation
+ private TestDatatypeProfile valueCodeableConcept; // Sexual Orientation
+
+ /**
+ * Parameter-less constructor. If you use this, the fixed values won't be filled
+ * out - they'll be missing. They'll be filled in if/when you call build, so they
+ * won't be missing from the resource, only from this particular object model
+ *
+ */
+ public TestProfile() {
+ // todo
+ }
+
+ /**
+ * Construct an instance of the object, and fill out all the fixed values
+ *
+ */
+ public TestProfile(IWorkerContext context) {
+ workerContext = context;
+ PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);
+ PEInstance src = builder.buildPEInstance(CANONICAL_URL, builder.createResource(CANONICAL_URL, false));
+ load(src);
+ }
+
+ /**
+ * Populate an instance of the object based on this source object
+ *
+ */
+ public static TestProfile fromSource(IWorkerContext context, Observation source) {
+ TestProfile theThing = new TestProfile();
+ theThing.workerContext = context;
+ PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);
+ PEInstance src = builder.buildPEInstance(CANONICAL_URL, source);
+ theThing.load(src);
+ return theThing;
+ }
+
+
+ public void load(PEInstance src) {
+ clear();
+ if (src.hasChild("id")) {
+ id = ((IdType) src.child("id").asDataType()).getValue();
+ }
+ for (PEInstance item : src.children("identifiers")) {
+ identifiers.add((Identifier) item.asDataType());
+ }
+ if (src.hasChild("status")) {
+ status = ((CodeType) src.child("status").asDataType()).getValue();
+ }
+ if (src.hasChild("code")) {
+ code = (CodeableConcept) src.child("code").asDataType();
+ }
+ if (src.hasChild("subject")) {
+ subject = (Reference) src.child("subject").asDataType();
+ }
+ if (src.hasChild("encounter")) {
+ encounter = (Reference) src.child("encounter").asDataType();
+ }
+ if (src.hasChild("effective")) {
+ effective = ((DateTimeType) src.child("effective").asDataType()).getValue();
+ }
+ for (PEInstance item : src.children("performers")) {
+ performers.add((Reference) item.asDataType());
+ }
+ if (src.hasChild("valueCodeableConcept")) {
+ valueCodeableConcept = TestDatatypeProfile.fromSource(src.child("valueCodeableConcept"));
+ }
+
+ }
+
+ /**
+ * Build an instance of the object based on this source object
+ *
+ */
+ public Observation build(IWorkerContext context) {
+ workerContext = context;
+ Observation theThing = new Observation();
+ PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);
+ PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, theThing);
+ save(tgt, false);
+ return theThing;
+ }
+
+ /**
+ * Save this profile class into an existing resource (overwriting enything that
+ * exists in the profile)
+ *
+ */
+ public void save(IWorkerContext context, Observation dest, boolean nulls) {
+ workerContext = context;
+ PEBuilder builder = new PEBuilder(context, PEElementPropertiesPolicy.EXTENSION, true);
+ PEInstance tgt = builder.buildPEInstance(CANONICAL_URL, dest);
+ save(tgt, nulls);
+ }
+
+ public void save(PEInstance tgt, boolean nulls) {
+
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public String getId() {
+ return id;
+ }
+
+ public TestProfile setId(String value) {
+ this.id = value;
+ return this;
+ }
+
+ public boolean hasId() {
+ return id != null;
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public List getIdentifiers() {
+ if (identifiers == null) { identifiers = new ArrayList<>(); }
+ return identifiers;
+ }
+
+ public boolean hasIdentifiers() {
+ return identifiers != null && !identifiers.isEmpty();
+ }
+
+ public Identifier addIdentifier() {
+ Identifier theThing = new Identifier();
+ getIdentifiers().add(theThing);
+ return theThing;
+ }
+
+ public boolean hasIdentifier(Identifier item) {
+ return hasIdentifiers() && identifiers.contains(item);
+ }
+
+ public void removeIdentifier(Identifier item) {
+ if (hasIdentifier(item)) {
+ identifiers.remove(item);
+ }
+ }
+
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public String getStatus() {
+ return status;
+ }
+
+ public TestProfile setStatus(String value) {
+ this.status = value;
+ return this;
+ }
+
+ public boolean hasStatus() {
+ return status != null;
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public CodeableConcept getCode() {
+ if (code == null) { code = new CodeableConcept(); }
+ return code;
+ }
+
+ public boolean hasCode() {
+ return code != null;
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public Reference getSubject() {
+ if (subject == null) { subject = new Reference(); }
+ return subject;
+ }
+
+ public TestProfile setSubject(Reference value) {
+ this.subject = value;
+ return this;
+ }
+ public boolean hasSubject() {
+ return subject != null;
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public Reference getEncounter() {
+ if (encounter == null) { encounter = new Reference(); }
+ return encounter;
+ }
+
+ public TestProfile setEncounter(Reference value) {
+ this.encounter = value;
+ return this;
+ }
+ public boolean hasEncounter() {
+ return encounter != null;
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public Date getEffective() {
+ return effective;
+ }
+
+ public TestProfile setEffective(Date value) {
+ this.effective = value;
+ return this;
+ }
+
+ public boolean hasEffective() {
+ return effective != null;
+ }
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public List getPerformers() {
+ if (performers == null) { performers = new ArrayList<>(); }
+ return performers;
+ }
+
+ public boolean hasPerformers() {
+ return performers != null && !performers.isEmpty();
+ }
+
+ public Reference addPerformer() {
+ Reference theThing = new Reference();
+ getPerformers().add(theThing);
+ return theThing;
+ }
+
+ public boolean hasPerformer(Reference item) {
+ return hasPerformers() && performers.contains(item);
+ }
+
+ public void removePerformer(Reference item) {
+ if (hasPerformer(item)) {
+ performers.remove(item);
+ }
+ }
+
+
+ /**
+ * Test Observation Profile.
+ *
+ */
+ public TestDatatypeProfile getValueCodeableConcept() {
+ if (valueCodeableConcept == null) { valueCodeableConcept = new TestDatatypeProfile(); }
+ return valueCodeableConcept;
+ }
+
+ public TestProfile setValueCodeableConcept(TestDatatypeProfile value) {
+ this.valueCodeableConcept = value;
+ return this;
+ }
+ public boolean hasValueCodeableConcept() {
+ return valueCodeableConcept != null;
+ }
+
+
+
+ public void clear() {
+ id = null;
+ identifiers = null;
+ status = null;
+ code = null;
+ subject = null;
+ encounter = null;
+ effective = null;
+ performers = null;
+ valueCodeableConcept = null;
+
+ }
+
+}