From e38740ac20d48033199d21b75d2613962a11539b Mon Sep 17 00:00:00 2001 From: jamesagnew Date: Tue, 25 Feb 2014 08:43:55 -0500 Subject: [PATCH] Adding simple setters for primitives --- .../model/api/annotation/SimpleSetter.java | 24 ++++++ .../test/resources/example-uhn-profile.xml | 6 +- .../java/ca/uhn/fhir/starter/BaseParser.java | 54 +++++++++++++ .../ca/uhn/fhir/starter/ResourceParser.java | 5 -- .../uhn/fhir/starter/model/BaseElement.java | 4 +- .../java/ca/uhn/fhir/starter/model/Child.java | 80 +++++++++++-------- .../uhn/fhir/starter/model/SimpleSetter.java | 46 +++++++++++ .../src/main/resources/templates.vm | 24 +++++- 8 files changed, 199 insertions(+), 44 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/SimpleSetter.java create mode 100644 hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/SimpleSetter.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/SimpleSetter.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/SimpleSetter.java new file mode 100644 index 00000000000..53b38a6aadd --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/annotation/SimpleSetter.java @@ -0,0 +1,24 @@ +package ca.uhn.fhir.model.api.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marker annotation for a primitive setter method that can be used to + * indicate a "simple setter" method on a resource or composite type + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(value= {ElementType.CONSTRUCTOR}) +public @interface SimpleSetter { + // nothing for now + + + @Retention(RetentionPolicy.RUNTIME) + @Target(value= {ElementType.PARAMETER}) + public @interface Parameter { + String name(); + } + +} diff --git a/hapi-fhir-base/src/test/resources/example-uhn-profile.xml b/hapi-fhir-base/src/test/resources/example-uhn-profile.xml index 6cee58a618b..8fc3d6f773a 100644 --- a/hapi-fhir-base/src/test/resources/example-uhn-profile.xml +++ b/hapi-fhir-base/src/test/resources/example-uhn-profile.xml @@ -1,12 +1,16 @@ - + + + + + diff --git a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/BaseParser.java b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/BaseParser.java index 03ef8cdb823..fdae125b6d2 100644 --- a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/BaseParser.java +++ b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/BaseParser.java @@ -8,6 +8,8 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -21,11 +23,13 @@ import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; import ca.uhn.fhir.starter.model.BaseElement; import ca.uhn.fhir.starter.model.Child; import ca.uhn.fhir.starter.model.Extension; import ca.uhn.fhir.starter.model.Resource; import ca.uhn.fhir.starter.model.ResourceBlock; +import ca.uhn.fhir.starter.model.SimpleSetter.Parameter; import ca.uhn.fhir.starter.util.XMLUtils; public abstract class BaseParser { @@ -102,12 +106,61 @@ public abstract class BaseParser { } parent.getChildren().add(elem); + /* + * Find simple setters + */ + if (elem instanceof Child) { + scanForSimpleSetters(elem); + } + } write(resource); } + private void scanForSimpleSetters(Child theElem) { + Class childDt; + if (theElem.getReferenceTypesForMultiple().size() == 1) { + try { + childDt = Class.forName("ca.uhn.fhir.model.primitive." + theElem.getReferenceTypesForMultiple().get(0)); + } catch (ClassNotFoundException e) { + return; + } + } else { + return; + } + + for (Constructor nextConstructor : childDt.getConstructors()) { + SimpleSetter simpleSetter = nextConstructor.getAnnotation(SimpleSetter.class); + if (simpleSetter == null) { + continue; + } + + ca.uhn.fhir.starter.model.SimpleSetter ss = new ca.uhn.fhir.starter.model.SimpleSetter(); + ss.setDatatype(childDt.getSimpleName()); + theElem.getSimpleSetters().add(ss); + + Annotation[][] paramAnn = nextConstructor.getParameterAnnotations(); + Class[] paramTypes = nextConstructor.getParameterTypes(); + for (int i = 0; i < paramTypes.length; i++) { + Parameter p = new Parameter(); + p.setDatatype(paramTypes[0].getSimpleName()); + p.setParameter(findAnnotation(childDt, paramAnn[i], SimpleSetter.Parameter.class).name()); + ss.getParameters().add(p); + } + } + } + + private ca.uhn.fhir.model.api.annotation.SimpleSetter.Parameter findAnnotation(Class theBase, Annotation[] theAnnotations, Class theClass) { + for (Annotation next : theAnnotations) { + if (theClass.equals(next.annotationType())) { + return (ca.uhn.fhir.model.api.annotation.SimpleSetter.Parameter) next; + } + } + throw new IllegalArgumentException(theBase.getCanonicalName() + " has @" + SimpleSetter.class.getCanonicalName() + " constructor with no/invalid parameter annotation"); + } + public void setDirectory(String theDirectory) { myDirectory = theDirectory; } @@ -165,6 +218,7 @@ public abstract class BaseParser { VelocityEngine v = new VelocityEngine(); v.setProperty("resource.loader", "cp"); v.setProperty("cp.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + v.setProperty("runtime.references.strict", Boolean.TRUE); InputStream templateIs = ResourceParser.class.getResourceAsStream(getTemplate()); InputStreamReader templateReader = new InputStreamReader(templateIs); diff --git a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/ResourceParser.java b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/ResourceParser.java index b2ff62cfc52..1615a1b750a 100644 --- a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/ResourceParser.java +++ b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/ResourceParser.java @@ -1,10 +1,5 @@ package ca.uhn.fhir.starter; -import java.util.ArrayList; - -import ca.uhn.fhir.model.primitive.DateDt; -import ca.uhn.fhir.model.primitive.StringDt; -import ca.uhn.fhir.starter.model.Extension; public class ResourceParser extends BaseParser { private String myResourceName; diff --git a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/BaseElement.java b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/BaseElement.java index 58ba2d2d61c..39786bcb44b 100644 --- a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/BaseElement.java +++ b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/BaseElement.java @@ -1,5 +1,7 @@ package ca.uhn.fhir.starter.model; +import static org.apache.commons.lang.StringUtils.*; + import java.util.ArrayList; import java.util.List; @@ -48,7 +50,7 @@ public abstract class BaseElement { } public String getDefinition() { - return myDefinition; + return defaultString(myDefinition, ""); } public String getElementName() { diff --git a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/Child.java b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/Child.java index 7d15a8a363d..a2e6bf114b8 100644 --- a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/Child.java +++ b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/Child.java @@ -8,8 +8,10 @@ import ca.uhn.fhir.model.api.ResourceReference; public class Child extends BaseElement { - public boolean isBlock() { - return false; + private List mySimpleStters = new ArrayList(); + + public String getAnnotationType() { + return getSingleType(); } public String getCardMaxForChildAnnotation() { @@ -20,16 +22,21 @@ public class Child extends BaseElement { } } - public List getReferenceTypesForMultiple() { - ArrayList retVal = new ArrayList(); - for (String next : getType()) { - retVal.add(next + "Dt"); + /** + * Strips off "[x]" + */ + public String getElementNameSimplified() { + String elementName = getElementName(); + if (elementName.endsWith("[x]")) { + elementName = elementName.substring(0, elementName.length() - 3); } - return retVal; + return elementName; } - public String getAnnotationType() { - return getSingleType(); + public String getMethodName() { + String elementName = getElementNameSimplified(); + elementName = elementName.substring(0, 1).toUpperCase() + elementName.substring(1); + return elementName; } public String getReferenceType() { @@ -53,6 +60,35 @@ public class Child extends BaseElement { return retVal; } + public String getReferenceTypeForConstructor() { + return getReferenceType().replaceAll("^List<", "ArrayList<"); + } + + public List getReferenceTypesForMultiple() { + ArrayList retVal = new ArrayList(); + for (String next : getType()) { + retVal.add(next + "Dt"); + } + return retVal; + } + + public List getSimpleSetters() { + return mySimpleStters; + } + + public String getVariableName() { + String elementName = getMethodName(); + return "my" + elementName; + } + + public boolean isBlock() { + return false; + } + + public boolean isRepeatable() { + return "1".equals(getCardMax()) == false; + } + protected String getSingleType() { String retVal; String elemName = this.getType().get(0); @@ -65,30 +101,4 @@ public class Child extends BaseElement { return retVal; } - public boolean isRepeatable() { - return "1".equals(getCardMax()) == false; - } - - public String getVariableName() { - String elementName = getMethodName(); - return "my" + elementName; - } - - public String getMethodName() { - String elementName = getElementNameSimplified(); - elementName = elementName.substring(0, 1).toUpperCase() + elementName.substring(1); - return elementName; - } - - /** - * Strips off "[x]" - */ - public String getElementNameSimplified() { - String elementName = getElementName(); - if (elementName.endsWith("[x]")) { - elementName = elementName.substring(0, elementName.length() - 3); - } - return elementName; - } - } diff --git a/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/SimpleSetter.java b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/SimpleSetter.java new file mode 100644 index 00000000000..487730c11e6 --- /dev/null +++ b/hapi-fhir-starter/src/main/java/ca/uhn/fhir/starter/model/SimpleSetter.java @@ -0,0 +1,46 @@ +package ca.uhn.fhir.starter.model; + +import java.util.ArrayList; +import java.util.List; + +public class SimpleSetter { + + private List myParameters = new ArrayList(); + private String myDatatype; + + public String getDatatype() { + return myDatatype; + } + + public void setDatatype(String theDatatype) { + myDatatype = theDatatype; + } + + public List getParameters() { + return myParameters; + } + + public static class Parameter { + + private String myDatatype; + private String myParameter; + + public String getDatatype() { + return myDatatype; + } + + public String getParameter() { + return myParameter; + } + + public void setDatatype(String theDatatype) { + myDatatype = theDatatype; + } + + public void setParameter(String theParameter) { + myParameter = theParameter; + } + + } + +} diff --git a/hapi-fhir-starter/src/main/resources/templates.vm b/hapi-fhir-starter/src/main/resources/templates.vm index 49505c6d131..e414c265a8a 100644 --- a/hapi-fhir-starter/src/main/resources/templates.vm +++ b/hapi-fhir-starter/src/main/resources/templates.vm @@ -35,7 +35,8 @@ #macro ( childAccessors $childElements ) #foreach ( $child in $children ) /** - * Gets the value(s) for ${child.elementName} (${child.shortName}) + * Gets the value(s) for ${child.elementName}, creating it if it does + * not exist (${child.shortName}). Will not return null. * *

* Definition: @@ -43,11 +44,16 @@ *

*/ public ${child.referenceType} get${child.methodName}() { +#if ( $!child.hasMultipleTypes ) + if (${child.variableName} == null) { + ${child.variableName} = new ${child.referenceTypeForConstructor}(); + } +#end return ${child.variableName}; } /** - * Sets the value(s) for ${child.elementName} (${child.shortName}) + * Sets the value(s) for ${child.elementName} (${child.shortName}) * *

* Definition: @@ -58,6 +64,20 @@ ${child.variableName} = theValue; } +#foreach ( $ss in $child.simpleSetters ) + /** + * Sets the value(s) for ${child.elementName} (${child.shortName}) + * + *

+ * Definition: + * ${child.definition} + *

+ */ + public void set${child.methodName}(#{foreach}($param in $ss.parameters) ${param.datatype} ${param.parameter}#{if}( $foreach.hasNext ), #{end}#{end}) { + ${child.variableName} = new ${ss.datatype}(#{foreach}($param in $ss.parameters) ${param.parameter}#{if}( $foreach.hasNext ), #{end}#{end}); + } + +#end #end #end