Fix #50 - Primitive datatypes now retain their textual values as well as the "parsed" values
This commit is contained in:
parent
cfcad3aabf
commit
1b7586f7ed
|
@ -29,7 +29,7 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
|
|||
|
||||
private T myCoercedValue;
|
||||
private String myStringValue;
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object theObj) {
|
||||
if (theObj == null) {
|
||||
|
@ -72,6 +72,7 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
|
|||
if (theValue == null) {
|
||||
myStringValue = null;
|
||||
} else {
|
||||
// NB this might be null
|
||||
myStringValue = encode(theValue);
|
||||
}
|
||||
}
|
||||
|
@ -82,23 +83,26 @@ public abstract class BasePrimitive<T> extends BaseIdentifiableElement implement
|
|||
if (theValue == null) {
|
||||
myCoercedValue = null;
|
||||
} else {
|
||||
// NB this might be null
|
||||
myCoercedValue = parse(theValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses must override to convert an encoded representation of
|
||||
* this datatype into a "coerced" one
|
||||
* Subclasses must override to convert an encoded representation of this datatype into a "coerced" one
|
||||
*
|
||||
* @param theValue Will not be null
|
||||
* @param theValue
|
||||
* Will not be null
|
||||
* @return May return null if the value does not correspond to anything
|
||||
*/
|
||||
protected abstract T parse(String theValue);
|
||||
|
||||
/**
|
||||
* Subclasses must override to convert a "coerced" value into an
|
||||
* encoded one.
|
||||
* Subclasses must override to convert a "coerced" value into an encoded one.
|
||||
*
|
||||
* @param theValue Will not be null
|
||||
* @param theValue
|
||||
* Will not be null
|
||||
* @return May return null if the value does not correspond to anything
|
||||
*/
|
||||
protected abstract String encode(T theValue);
|
||||
|
||||
|
|
|
@ -33,7 +33,23 @@ import ca.uhn.fhir.parser.DataFormatException;
|
|||
@DatatypeDef(name = "uri")
|
||||
public class UriDt extends BasePrimitive<URI> {
|
||||
|
||||
private URI myValue;
|
||||
/**
|
||||
* Creates a new UriDt instance which uses the given OID as the content (and prepends "urn:oid:" to the OID string
|
||||
* in the value of the newly created UriDt, per the FHIR specification).
|
||||
*
|
||||
* @param theOid
|
||||
* The OID to use (<code>null</code> is acceptable and will result in a UriDt instance with a
|
||||
* <code>null</code> value)
|
||||
* @return A new UriDt instance
|
||||
*/
|
||||
public static UriDt fromOid(String theOid) {
|
||||
if (theOid == null) {
|
||||
return new UriDt();
|
||||
}
|
||||
return new UriDt("urn:oid:" + theOid);
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UriDt.class);
|
||||
|
||||
/**
|
||||
* Create a new String
|
||||
|
@ -51,57 +67,8 @@ public class UriDt extends BasePrimitive<URI> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public URI getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(URI theValue) {
|
||||
myValue = theValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
if (theValue == null) {
|
||||
myValue = null;
|
||||
} else {
|
||||
try {
|
||||
myValue = new URI(theValue);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new DataFormatException("Unable to parse URI value", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString() {
|
||||
if (myValue == null) {
|
||||
return null;
|
||||
} else {
|
||||
return myValue.toASCIIString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getValueAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((myValue == null) ? 0 : myValue.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the given string to the string representation of this URI. In many cases it is preferable to use this
|
||||
* instead of the standard {@link #equals(Object)} method, since that method returns <code>false</code> unless it is
|
||||
* passed an instance of {@link UriDt}
|
||||
*/
|
||||
public boolean equals(String theString) {
|
||||
return StringUtils.equals(getValueAsString(), theString);
|
||||
protected String encode(URI theValue) {
|
||||
return getValue().toASCIIString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -114,21 +81,42 @@ public class UriDt extends BasePrimitive<URI> {
|
|||
return false;
|
||||
|
||||
UriDt other = (UriDt) obj;
|
||||
if (myValue == null && other.myValue == null) {
|
||||
if (getValue() == null && other.getValue() == null) {
|
||||
return true;
|
||||
}
|
||||
if (myValue == null || other.myValue == null) {
|
||||
if (getValue() == null || other.getValue() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
URI normalize = normalize(myValue);
|
||||
URI normalize2 = normalize(other.myValue);
|
||||
URI normalize = normalize(getValue());
|
||||
URI normalize2 = normalize(other.getValue());
|
||||
return normalize.equals(normalize2);
|
||||
}
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UriDt.class);
|
||||
/**
|
||||
* Compares the given string to the string representation of this URI. In many cases it is preferable to use this
|
||||
* instead of the standard {@link #equals(Object)} method, since that method returns <code>false</code> unless it is
|
||||
* passed an instance of {@link UriDt}
|
||||
*/
|
||||
public boolean equals(String theString) {
|
||||
return StringUtils.equals(getValueAsString(), theString);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
|
||||
URI normalize = normalize(getValue());
|
||||
result = prime * result + ((normalize == null) ? 0 : normalize.hashCode());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private URI normalize(URI theValue) {
|
||||
if (theValue == null) {
|
||||
return null;
|
||||
}
|
||||
URI retVal = (theValue.normalize());
|
||||
String urlString = retVal.toString();
|
||||
if (urlString.endsWith("/") && urlString.length() > 1) {
|
||||
|
@ -141,20 +129,13 @@ public class UriDt extends BasePrimitive<URI> {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new UriDt instance which uses the given OID as the content (and prepends "urn:oid:" to the OID string
|
||||
* in the value of the newly created UriDt, per the FHIR specification).
|
||||
*
|
||||
* @param theOid
|
||||
* The OID to use (<code>null</code> is acceptable and will result in a UriDt instance with a
|
||||
* <code>null</code> value)
|
||||
* @return A new UriDt instance
|
||||
*/
|
||||
public static UriDt fromOid(String theOid) {
|
||||
if (theOid == null) {
|
||||
return new UriDt();
|
||||
@Override
|
||||
protected URI parse(String theValue) {
|
||||
try {
|
||||
return new URI(theValue);
|
||||
} catch (URISyntaxException e) {
|
||||
throw new DataFormatException("Unable to parse URI value", e);
|
||||
}
|
||||
return new UriDt("urn:oid:" + theOid);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -41,8 +41,6 @@ import ca.uhn.fhir.util.XmlUtil;
|
|||
@DatatypeDef(name = "xhtml")
|
||||
public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
||||
|
||||
private List<XMLEvent> myValue;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -73,18 +71,23 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
*/
|
||||
@Override
|
||||
public void setValueAsString(String theValue) throws DataFormatException {
|
||||
if (theValue == null) {
|
||||
myValue = null;
|
||||
return;
|
||||
}
|
||||
// This method is only here for providing specialized javadocs
|
||||
super.setValueAsString(theValue);
|
||||
}
|
||||
|
||||
|
||||
public boolean hasContent() {
|
||||
return getValue() != null && getValue().size() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<XMLEvent> parse(String theValue) {
|
||||
String val = theValue.trim();
|
||||
if (!val.startsWith("<")) {
|
||||
val = "<div>" + val + "</div>";
|
||||
}
|
||||
if (val.startsWith("<?") && val.endsWith("?>")) {
|
||||
myValue = null;
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -103,7 +106,7 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
value.add(next);
|
||||
}
|
||||
}
|
||||
setValue(value);
|
||||
return value;
|
||||
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("String does not appear to be valid XML/XHTML (error is \"" + e.getMessage() + "\"): " + theValue, e);
|
||||
|
@ -113,14 +116,11 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getValueAsString() throws DataFormatException {
|
||||
if (myValue == null) {
|
||||
return null;
|
||||
}
|
||||
protected String encode(List<XMLEvent> theValue) {
|
||||
try {
|
||||
StringWriter w = new StringWriter();
|
||||
XMLEventWriter ew = XmlUtil.createXmlWriter(w);
|
||||
for (XMLEvent next : myValue) {
|
||||
for (XMLEvent next : getValue()) {
|
||||
if (next.isCharacters()) {
|
||||
ew.add(next);
|
||||
} else {
|
||||
|
@ -136,18 +136,4 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<XMLEvent> getValue() {
|
||||
return myValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setValue(List<XMLEvent> theValue) throws DataFormatException {
|
||||
myValue = theValue;
|
||||
}
|
||||
|
||||
public boolean hasContent() {
|
||||
return myValue != null && myValue.size() > 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<faceted-project>
|
||||
<installed facet="jst.utility" version="1.0"/>
|
||||
<installed facet="java" version="1.6"/>
|
||||
<installed facet="java" version="1.7"/>
|
||||
</faceted-project>
|
||||
|
|
|
@ -37,9 +37,10 @@ public class BaseDateTimeDtTest {
|
|||
@Test()
|
||||
public void testParseMalformatted() throws DataFormatException {
|
||||
DateTimeDt dt = new DateTimeDt("20120102");
|
||||
assertEquals("2012-01-02",dt.getValueAsString());
|
||||
}
|
||||
|
||||
assertEquals("20120102", dt.getValueAsString());
|
||||
assertEquals("2012-01-02", new SimpleDateFormat("yyyy-MM-dd").format(dt.getValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMonth() throws DataFormatException {
|
||||
DateTimeDt dt = new DateTimeDt();
|
||||
|
|
|
@ -50,6 +50,15 @@ public class XhtmlDtTest {
|
|||
assertEquals("<div>amp &</div>", x.getValueAsString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyProcessingDirective() {
|
||||
XhtmlDt x = new XhtmlDt();
|
||||
x.setValueAsString("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
|
||||
assertEquals(null, x.getValue());
|
||||
assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>", x.getValueAsString());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testCharacterEntities() {
|
||||
|
|
|
@ -5,10 +5,14 @@ import ca.uhn.fhir.model.api.Bundle;
|
|||
import ca.uhn.fhir.model.dstu.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu.resource.Patient;
|
||||
import ca.uhn.fhir.model.dstu.valueset.ContactSystemEnum;
|
||||
import ca.uhn.fhir.model.primitive.DateTimeDt;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
@ -31,7 +35,7 @@ public class ResourceValidatorTest {
|
|||
FhirValidator val = ourCtx.newValidator();
|
||||
val.setValidateAgainstStandardSchema(true);
|
||||
val.setValidateAgainstStandardSchematron(false);
|
||||
|
||||
|
||||
val.validate(p);
|
||||
|
||||
p.getAnimal().getBreed().setText("The Breed");
|
||||
|
@ -45,18 +49,43 @@ public class ResourceValidatorTest {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See issue #50
|
||||
*/
|
||||
@Test
|
||||
public void testOutOfBoundsDate() {
|
||||
Patient p = new Patient();
|
||||
p.setBirthDate(new DateTimeDt("2000-15-31"));
|
||||
|
||||
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
|
||||
ourLog.info(encoded);
|
||||
|
||||
assertThat(encoded, StringContains.containsString("2000-15-31"));
|
||||
|
||||
p = ourCtx.newXmlParser().parseResource(Patient.class, encoded);
|
||||
assertEquals("2000-15-31", p.getBirthDate().getValueAsString());
|
||||
assertEquals("2001-03-31", new SimpleDateFormat("yyyy-MM-dd").format(p.getBirthDate().getValue()));
|
||||
|
||||
ValidationResult result = ourCtx.newValidator().validateWithResult(p);
|
||||
String resultString = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.getOperationOutcome());
|
||||
ourLog.info(resultString);
|
||||
|
||||
assertEquals(2, result.getOperationOutcome().getIssue().size());
|
||||
assertThat(resultString, StringContains.containsString("cvc-datatype-valid.1.2.3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaBundleValidator() throws IOException {
|
||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||
|
||||
FhirValidator val = createFhirValidator();
|
||||
FhirValidator val = createFhirValidator();
|
||||
|
||||
val.validate(b);
|
||||
|
||||
Patient p = (Patient) b.getEntries().get(0).getResource();
|
||||
p.getTelecomFirstRep().setValue("123-4567");
|
||||
|
||||
|
||||
try {
|
||||
val.validate(b);
|
||||
fail();
|
||||
|
@ -76,60 +105,60 @@ public class ResourceValidatorTest {
|
|||
val.setValidateAgainstStandardSchema(false);
|
||||
val.setValidateAgainstStandardSchematron(true);
|
||||
|
||||
ValidationResult validationResult = val.validateWithResult(p);
|
||||
assertTrue(validationResult.isSuccessful());
|
||||
ValidationResult validationResult = val.validateWithResult(p);
|
||||
assertTrue(validationResult.isSuccessful());
|
||||
|
||||
p.getTelecomFirstRep().setValue("123-4567");
|
||||
validationResult = val.validateWithResult(p);
|
||||
assertFalse(validationResult.isSuccessful());
|
||||
OperationOutcome operationOutcome = (OperationOutcome) validationResult.getOperationOutcome();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
|
||||
assertEquals(1, operationOutcome.getIssue().size());
|
||||
assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
||||
p.getTelecomFirstRep().setValue("123-4567");
|
||||
validationResult = val.validateWithResult(p);
|
||||
assertFalse(validationResult.isSuccessful());
|
||||
OperationOutcome operationOutcome = (OperationOutcome) validationResult.getOperationOutcome();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
|
||||
assertEquals(1, operationOutcome.getIssue().size());
|
||||
assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
||||
|
||||
p.getTelecomFirstRep().setSystem(ContactSystemEnum.EMAIL);
|
||||
validationResult = val.validateWithResult(p);
|
||||
assertTrue(validationResult.isSuccessful());
|
||||
validationResult = val.validateWithResult(p);
|
||||
assertTrue(validationResult.isSuccessful());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaBundleValidatorIsSuccessful() throws IOException {
|
||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||
@Test
|
||||
public void testSchemaBundleValidatorIsSuccessful() throws IOException {
|
||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||
|
||||
FhirValidator val = createFhirValidator();
|
||||
FhirValidator val = createFhirValidator();
|
||||
|
||||
ValidationResult result = val.validateWithResult(b);
|
||||
assertTrue(result.isSuccessful());
|
||||
OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
|
||||
assertNotNull(operationOutcome);
|
||||
assertEquals(0, operationOutcome.getIssue().size());
|
||||
}
|
||||
ValidationResult result = val.validateWithResult(b);
|
||||
assertTrue(result.isSuccessful());
|
||||
OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome();
|
||||
assertNotNull(operationOutcome);
|
||||
assertEquals(0, operationOutcome.getIssue().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSchemaBundleValidatorFails() throws IOException {
|
||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||
@Test
|
||||
public void testSchemaBundleValidatorFails() throws IOException {
|
||||
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml"));
|
||||
Bundle b = ourCtx.newXmlParser().parseBundle(res);
|
||||
|
||||
FhirValidator val = createFhirValidator();
|
||||
FhirValidator val = createFhirValidator();
|
||||
|
||||
ValidationResult validationResult = val.validateWithResult(b);
|
||||
assertTrue(validationResult.isSuccessful());
|
||||
ValidationResult validationResult = val.validateWithResult(b);
|
||||
assertTrue(validationResult.isSuccessful());
|
||||
|
||||
Patient p = (Patient) b.getEntries().get(0).getResource();
|
||||
p.getTelecomFirstRep().setValue("123-4567");
|
||||
validationResult = val.validateWithResult(b);
|
||||
assertFalse(validationResult.isSuccessful());
|
||||
OperationOutcome operationOutcome = (OperationOutcome) validationResult.getOperationOutcome();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
|
||||
assertEquals(1, operationOutcome.getIssue().size());
|
||||
assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
||||
}
|
||||
Patient p = (Patient) b.getEntries().get(0).getResource();
|
||||
p.getTelecomFirstRep().setValue("123-4567");
|
||||
validationResult = val.validateWithResult(b);
|
||||
assertFalse(validationResult.isSuccessful());
|
||||
OperationOutcome operationOutcome = (OperationOutcome) validationResult.getOperationOutcome();
|
||||
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
|
||||
assertEquals(1, operationOutcome.getIssue().size());
|
||||
assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided."));
|
||||
}
|
||||
|
||||
private FhirValidator createFhirValidator() {
|
||||
FhirValidator val = ourCtx.newValidator();
|
||||
val.setValidateAgainstStandardSchema(true);
|
||||
val.setValidateAgainstStandardSchematron(true);
|
||||
return val;
|
||||
}
|
||||
private FhirValidator createFhirValidator() {
|
||||
FhirValidator val = ourCtx.newValidator();
|
||||
val.setValidateAgainstStandardSchema(true);
|
||||
val.setValidateAgainstStandardSchematron(true);
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,16 @@
|
|||
but the version bundled with IBM's JDK is flaky and resulted in a number
|
||||
of problems when deploying to Websphere.
|
||||
</action>
|
||||
<action type="fix" issue="50">
|
||||
Primitive datatypes now preserve their original string value when parsing resources,
|
||||
as well as containing the "parsed value". For instance, a DecimalDt field value of
|
||||
<![CDATA[<code>1.0000</code>]]> will be parsed into the corresponding
|
||||
decimal value, but will also retain the original value with the corresponding
|
||||
level of precision. This allows vadliator rules to be applied to
|
||||
original values as received "over the wire", such as well formatted but
|
||||
invalid dates, e.g. "2001-15-01". Thanks to Joe Athman for reporting and
|
||||
helping to come up with a fix!
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.7" date="2014-Oct-23">
|
||||
<action type="add" issue="30">
|
||||
|
|
|
@ -1,476 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<document xmlns="http://maven.apache.org/changes/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 ./changes.xsd">
|
||||
<properties>
|
||||
<author>James Agnew</author>
|
||||
<title>HAPI FHIR Changelog</title>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="0.8" date="TBD">
|
||||
<<<<<<< HEAD:src/changes/changes.xml
|
||||
<action type="add" issue="38">
|
||||
Profile generation on the server was not working due to IdDt being
|
||||
incorrectly used. Thanks to Bill de Beaubien for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="42">
|
||||
=======
|
||||
<action>
|
||||
<![CDATA[<b>API CHANGE:</b>]]> The "FHIR structures" for DSTU1 (the classes which model the
|
||||
resources and composite datatypes) have been moved out of the core JAR into their
|
||||
own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast
|
||||
version is finalized. See
|
||||
<![CDATA[<a href="./doc_upgrading.html">upgrading</a>]]>
|
||||
for more information.
|
||||
</action>
|
||||
<action type="add" issue="38" dev="wdebeau1">
|
||||
Profile generation on the server was not working due to IdDt being
|
||||
incorrectly used. Thanks to Bill de Beaubien for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="42" dev="wdebeau1">
|
||||
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:src/changes/changes.xml
|
||||
Profiles did not generate correctly if a resource definition class had a
|
||||
defined extension which was of a composite type. Thanks to Bill de Beaubien for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="44" dev="petromykhailysyn">
|
||||
Remove unnessecary IOException from narrative generator API. Thanks to
|
||||
Petro Mykhailysyn for the pull request!
|
||||
</action>
|
||||
<<<<<<< HEAD:src/changes/changes.xml
|
||||
=======
|
||||
<action type="add" issue="48" dev="wdebeau1">
|
||||
Introduced a new
|
||||
<![CDATA[<code>@ProvidesResources</code>]]> annotation which can be added to
|
||||
resource provider and servers to allow them to declare additional resource
|
||||
classes they are able to serve. This is useful if you have a server which can
|
||||
serve up multiple classes for the same resource type (e.g. a server that sometimes
|
||||
returns a default Patient, but sometimes uses a custom subclass).
|
||||
Thanks to Bill de Beaubien for the pull request!
|
||||
</action>
|
||||
<action>
|
||||
Add a new method <![CDATA[handleException]]> to the server interceptor
|
||||
framework which allows interceptors to be notified of any exceptions and
|
||||
runtime errors within server methods. Interceptors may optionally also
|
||||
override the default error handling behaviour of the RestfulServer.
|
||||
</action>
|
||||
<action dev="wdebeau1">
|
||||
Add constants to BaseResource for the "_id" search parameter which all resources
|
||||
should support.
|
||||
</action>
|
||||
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:src/changes/changes.xml
|
||||
</release>
|
||||
<release version="0.7" date="2014-Oct-23">
|
||||
<action type="add" issue="30">
|
||||
<![CDATA[<b>API CHANGE:</b>]]> The TagList class previously implemented ArrayList semantics,
|
||||
but this has been replaced with LinkedHashMap semantics. This means that the list of
|
||||
tags will no longer accept duplicate tags, but that tag order will still be
|
||||
preserved. Thanks to Bill de Beaubien for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="33">
|
||||
Server was incorrectly including contained resources being returned as both contained resources, and as
|
||||
top-level resources in the returned bundle for search operations.
|
||||
Thanks to Bill de Beaubien for reporting! This also fixes Issue #20, thanks to
|
||||
lephty for reporting!
|
||||
</action>
|
||||
<action type="add" dev="suranga">
|
||||
Documentation fixes
|
||||
</action>
|
||||
<action type="add" dev="dougmartin">
|
||||
Add a collection of new methods on the generic client which support the
|
||||
<![CDATA[
|
||||
<b><a href="./apidocs/ca/uhn/fhir/rest/client/IGenericClient.html#read(java.lang.Class,%20ca.uhn.fhir.model.primitive.UriDt)">read</a></b>,
|
||||
<b><a href="./apidocs/ca/uhn/fhir/rest/client/IGenericClient.html#vread(java.lang.Class,%20ca.uhn.fhir.model.primitive.UriDt)">read</a></b>,
|
||||
and <b><a href="./apidocs/ca/uhn/fhir/rest/client/IGenericClient.html#search(java.lang.Class,%20ca.uhn.fhir.model.primitive.UriDt)">search</a></b>
|
||||
]]>
|
||||
operations using an absolute URL. This allows developers to perform these operations using
|
||||
URLs they obtained from other sources (or external resource references within resources). In
|
||||
addition, the existing read/vread operations will now access absolute URL references if
|
||||
they are passed in. Thanks to Doug Martin of the Regenstrief Center for Biomedical Informatics
|
||||
for contributing this implementation!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server implementation was not correctly figuring out its own FHIR Base URL when deployed
|
||||
on Amazon Web Service server. Thanks to Jeffrey Ting and Bill De Beaubien of
|
||||
Systems Made Simple for their help in figuring out this issue!
|
||||
</action>
|
||||
<action type="fix">
|
||||
XML Parser failed to encode fields with both a resource reference child and
|
||||
a primitive type child. Thanks to Jeffrey Ting and Bill De Beaubien of
|
||||
Systems Made Simple for their help in figuring out this issue!
|
||||
</action>
|
||||
<action type="fix">
|
||||
HAPI now runs successfully on Servlet 2.5 containers (such as Tomcat 6). Thanks to
|
||||
Bernard Gitaadji for reporting and diagnosing the issue!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Summary (in the bundle entry) is now encoded by the XML and JSON parsers if supplied. Thanks to David Hay of
|
||||
Orion Health for reporting this!
|
||||
</action>
|
||||
<action type="fix" issue="24">
|
||||
Conformance profiles which are automatically generated by the server were missing a few mandatory elements,
|
||||
which meant that the profile did not correctly validate. Thanks to Bill de Beaubien of Systems Made Simple
|
||||
for reporting this!
|
||||
</action>
|
||||
<action type="fix">
|
||||
XHTML (in narratives) containing escapable characters (e.g. < or ") will now always have those characters
|
||||
escaped properly in encoded messages.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Resources containing entities which are not valid in basic XML (e.g. &sect;) will have those
|
||||
entities converted to their equivalent unicode characters when resources are encoded, since FHIR does
|
||||
not allow extended entities in resource instances.
|
||||
</action>
|
||||
<action type="add">
|
||||
Add a new client interceptor which adds HTTP Authorization Bearer Tokens (for use with OAUTH2 servers)
|
||||
to client requests.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Add phloc-commons dependency explicitly, which resolves an issue building HAPI from source on
|
||||
some platforms. Thanks to Odysseas Pentakalos for the patch!
|
||||
</action>
|
||||
<action type="add">
|
||||
HAPI now logs a single line indicating the StAX implementation being used upon the
|
||||
first time an XML parser is created.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Update methods on the server did not return a "content-location" header, but
|
||||
only a "location" header. Both are required according to the FHIR specification.
|
||||
Thanks to Bill de Beaubien of Systems Made Simple for reporting this!
|
||||
</action>
|
||||
<action type="fix" issue="26" dev="akley">
|
||||
Parser failed to correctly read contained Binary resources. Thanks to Alexander Kley for
|
||||
the patch!
|
||||
</action>
|
||||
<action type="fix" issue="29" dev="akley">
|
||||
Calling encode multiple times on a resource with contained resources caused the contained
|
||||
resources to be re-added (and the actual message to grow) with each encode pass. Thanks to
|
||||
Alexander Kley for the test case!
|
||||
</action>
|
||||
<action type="fix">
|
||||
JSON-encoded contained resources with the incorrect "_id" element (which should be "id", but some
|
||||
incorrect examples exist on the FHIR specification) now parse correctly. In other words, HAPI
|
||||
previously only accepted the correct "id" element, but now it also accepts the incorrect
|
||||
"_id" element just to be more lenient.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Several unit tests failed on Windows (or any platform with non UTF-8 default encoding). This may
|
||||
have also caused resource validation to fail occasionally on these platforms as well.
|
||||
Thanks to Bill de Beaubien for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
toString() method on TokenParam was incorrectly showing the system as the value.
|
||||
Thanks to Bill de Beaubien for reporting!
|
||||
</action>
|
||||
<action type="update">
|
||||
Documentation on contained resources contained a typo and did not actually produce contained resources. Thanks
|
||||
to David Hay of Orion Health for reporting!
|
||||
</action>
|
||||
<action type="add" issue="31" dev="preston">
|
||||
Add a
|
||||
<![CDATA[<a href="https://www.vagrantup.com/">Vagrant</a>]]>
|
||||
based environment (basically a fully built, self contained development environment) for
|
||||
trying out the HAPI server modules. Thanks to Preston Lee for the pull request, and for
|
||||
offering to maintain this!
|
||||
</action>
|
||||
<action type="add" issue="32" dev="jathman">
|
||||
Change validation API so that it uses a return type instead of exceptions to communicate
|
||||
validation failures. Thanks to Joe Athman for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="35" dev="petromykhailysyn">
|
||||
Add a client interceptor which adds an HTTP cookie to each client request. Thanks to
|
||||
Petro Mykhailysyn for the pull request!
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.6" date="2014-Sep-08" description="This release brings a number of new features and bug fixes!">
|
||||
<!--
|
||||
<action type="add">
|
||||
Allow generic client ... OAUTH
|
||||
</action>
|
||||
-->
|
||||
<action type="add">
|
||||
Add server interceptor framework, and new interceptor for logging incoming
|
||||
requests.
|
||||
</action>
|
||||
<action type="add">
|
||||
Add server validation framework for validating resources against the FHIR schemas and schematrons
|
||||
</action>
|
||||
<action type="fix">
|
||||
Tester UI created double _format and _pretty param entries in searches. Thanks to Gered King of University
|
||||
Health Network for reporting!
|
||||
</action>
|
||||
<action type="fix" issue="4">
|
||||
Create method was incorrectly returning an HTTP 204 on sucessful completion, but
|
||||
should be returning an HTTP 200 per the FHIR specification. Thanks to wanghaisheng
|
||||
for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
FHIR Tester UI now correctly sends UTF-8 charset in responses so that message payloads containing
|
||||
non US-ASCII characters will correctly display in the browser
|
||||
</action>
|
||||
<action type="fix">
|
||||
JSON parser was incorrectly encoding extensions on composite elements outside the element itself
|
||||
(as is done correctly for non-composite elements) instead of inside of them. Thanks to David Hay of
|
||||
Orion for reporting this!
|
||||
</action>
|
||||
<action type="add">
|
||||
Contained/included resource instances received by a client are now automatically
|
||||
added to any ResourceReferenceDt instancea in other resources which reference them.
|
||||
</action>
|
||||
<action type="add">
|
||||
Add documentation on how to use eBay CORS Filter to support Cross Origin Resource
|
||||
Sharing (CORS) to server. CORS support that was built in to the server itself has
|
||||
been removed, as it did not work correctly (and was reinventing a wheel that others
|
||||
have done a great job inventing). Thanks to Peter Bernhardt of Relay Health for all the assistance
|
||||
in testing this!
|
||||
</action>
|
||||
<action type="fix">
|
||||
IResource interface did not expose the getLanguage/setLanguage methods from BaseResource,
|
||||
so the resource language was difficult to access.
|
||||
</action>
|
||||
<action type="fix">
|
||||
JSON Parser now gives a more friendly error message if it tries to parse JSON with invalid use
|
||||
of single quotes
|
||||
</action>
|
||||
<action type="add">
|
||||
Transaction server method is now allowed to return an OperationOutcome in addition to the
|
||||
incoming resources. The public test server now does this in order to return status information
|
||||
about the transaction processing.
|
||||
</action>
|
||||
<action type="add">
|
||||
Update method in the server can now flag (via a field on the MethodOutcome object being returned)
|
||||
that the result was actually a creation, and Create method can indicate that it was actually an
|
||||
update. This has no effect other than to switch between the HTTP 200 and HTTP 201 status codes on the
|
||||
response, but this may be useful in some circumstances.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Annotation client search methods with a specific resource type (e.g. List<Patient> search())
|
||||
won't return any resources that aren't of the correct type that are received in a response
|
||||
bundle (generally these are referenced resources, so they are populated in the reference fields instead).
|
||||
Thanks to Tahura Chaudhry of University Health Network for the unit test!
|
||||
</action>
|
||||
<action type="add">
|
||||
Added narrative generator template for OperationOutcome resource
|
||||
</action>
|
||||
<action type="fix">
|
||||
Date/time types did not correctly parse values in the format "yyyymmdd" (although the FHIR-defined format
|
||||
is "yyyy-mm-dd" anyhow, and this is correctly handled). Thanks to Jeffrey Ting of Systems Made Simple
|
||||
for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server search method for an unnamed query gets called if the client requests a named query
|
||||
with the same parameter list. Thanks to Neal Acharya of University Health Network for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Category header (for tags) is correctly read in client for "read" operation
|
||||
</action>
|
||||
<action type="add">
|
||||
Transaction method in server can now have parameter type Bundle instead of
|
||||
List<IResource>
|
||||
</action>
|
||||
<action type="add">
|
||||
HAPI parsers now use field access to get/set values instead of method accessors and mutators.
|
||||
This should give a small performance boost.
|
||||
</action>
|
||||
<action type="fix">
|
||||
JSON parser encodes resource references incorrectly, using the name "resource" instead
|
||||
of the name "reference" for the actual reference. Thanks to
|
||||
Ricky Nguyen for reporting and tracking down the issue!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Rename NotImpementedException to NotImplementedException (to correct typo)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server setUseBrowserFriendlyContentType setting also respected for errors (e.g. OperationOutcome with 4xx/5xx status)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Fix performance issue in date/time datatypes where pattern matchers were not static
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server now gives a more helpful error message if a @Read method has a search parameter (which is invalid, but
|
||||
previously lead to a very unhelpful error message). Thanks to Tahura Chaudhry of UHN for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Resource of type "List" failed to parse from a bundle correctly. Thanks to David Hay of Orion Health
|
||||
for reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
QuantityParam correctly encodes approximate (~) prefix to values
|
||||
</action>
|
||||
<action type="fix" issue="14">
|
||||
If a server defines a method with parameter "_id", incoming search requests for that method may
|
||||
get delegated to the wrong method. Thanks to Neal Acharya for reporting!
|
||||
</action>
|
||||
<action type="add">
|
||||
SecurityEvent.Object structural element has been renamed to
|
||||
SecurityEvent.ObjectElement to avoid conflicting names with the
|
||||
java Object class. Thanks to Laurie Macdougall-Sookraj of UHN for
|
||||
reporting!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Text/narrative blocks that were created with a non-empty
|
||||
namespace prefix (e.g. <xhtml:div xmlns:xhtml="...">...</xhtml:div>)
|
||||
failed to encode correctly (prefix was missing in encoded resource)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Resource references previously encoded their children (display and reference)
|
||||
in the wrong order so references with both would fail schema validation.
|
||||
</action>
|
||||
<action type="add">
|
||||
SecurityEvent resource's enums now use friendly enum names instead of the unfriendly
|
||||
numeric code values. Thanks to Laurie MacDougall-Sookraj of UHN for the
|
||||
suggestion!
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.5" date="2014-Jul-30">
|
||||
<action type="add">
|
||||
HAPI has a number of RESTful method parameter types that have similar but not identical
|
||||
purposes and confusing names. A cleanup has been undertaken to clean this up.
|
||||
This means that a number of existing classes
|
||||
have been deprocated in favour of new naming schemes.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
All annotation-based clients and all server search method parameters are now named
|
||||
(type)Param, for example: StringParam, TokenParam, etc.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
All generic/fluent client method parameters are now named
|
||||
(type)ClientParam, for example: StringClientParam, TokenClientParam, etc.
|
||||
<![CDATA[<br/><br/>]]>
|
||||
All renamed classes have been retained and deprocated, so this change should not cause any issues
|
||||
for existing applications but those applications should be refactored to use the
|
||||
new parameters when possible.
|
||||
</action>
|
||||
<action type="add">
|
||||
Allow server methods to return wildcard generic types (e.g. List<? extends IResource>)
|
||||
</action>
|
||||
<action type="add">
|
||||
Search parameters are not properly escaped and unescaped. E.g. for a token parameter such as
|
||||
"&identifier=system|codepart1\|codepart2"
|
||||
</action>
|
||||
<action type="add">
|
||||
Add support for OPTIONS verb (which returns the server conformance statement)
|
||||
</action>
|
||||
<action type="add">
|
||||
Add support for CORS headers in server
|
||||
</action>
|
||||
<action type="add">
|
||||
Bump SLF4j dependency to latest version (1.7.7)
|
||||
</action>
|
||||
<action type="add">
|
||||
Add interceptor framework for clients (annotation based and generic), and add interceptors
|
||||
for configurable logging, capturing requests and responses, and HTTP basic auth.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Transaction client invocations with XML encoding were using the wrong content type ("application/xml+fhir" instead
|
||||
of the correct "application/atom+xml"). Thanks to David Hay of Orion Health for surfacing this one!
|
||||
</action>
|
||||
<action type="add">
|
||||
Bundle entries now support a link type of "search". Thanks to David Hay for the suggestion!
|
||||
</action>
|
||||
<action type="add" issue="1">
|
||||
If a client receives a non 2xx response (e.g. HTTP 500) and the response body is a text/plain message or
|
||||
an OperationOutcome resource, include the message in the exception message so that it will be
|
||||
more conveniently displayed in logs and other places. Thanks to Neal Acharya for the suggestion!
|
||||
</action>
|
||||
<action type="add" issue="2">
|
||||
Read invocations in the client now process the "Content-Location" header and use it to
|
||||
populate the ID of the returned resource. Thanks to Neal Acharya for the suggestion!
|
||||
</action>
|
||||
<action type="fix" issue="3">
|
||||
Fix issue where vread invocations on server incorrectly get routed to instance history method if one is
|
||||
defined. Thanks to Neal Acharya from UHN for surfacing this one!
|
||||
</action>
|
||||
<action type="add">
|
||||
Binary reads on a server not include the Content-Disposition header, to prevent HTML in binary
|
||||
blobs from being used for nefarious purposes. See
|
||||
<![CDATA[<a href="http://gforge.hl7.org/gf/project/fhir/tracker/?action=TrackerItemEdit&tracker_id=677&tracker_item_id=3298">FHIR Tracker Bug 3298</a>]]>
|
||||
for more information.
|
||||
</action>
|
||||
<action type="add">
|
||||
Support has been added for using an HTTP proxy for outgoing requests.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Fix: Primitive extensions declared against custom resource types
|
||||
are encoded even if they have no value. Thanks to David Hay of Orion for
|
||||
reporting this!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Fix: RESTful server deployed to a location where the URL to access it contained a
|
||||
space (e.g. a WAR file with a space in the name) failed to work correctly.
|
||||
Thanks to David Hay of Orion for reporting this!
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.4" date="2014-Jul-13">
|
||||
<action type="add">
|
||||
<![CDATA[<b>BREAKING CHANGE:</b>]]>: IdDt has been modified so that it
|
||||
contains a partial or complete resource identity. Previously it contained
|
||||
only the simple alphanumeric id of the resource (the part at the end of the "read" URL for
|
||||
that resource) but it can now contain a complete URL or even a partial URL (e.g. "Patient/123")
|
||||
and can optionally contain a version (e.g. "Patient/123/_history/456"). New methods have
|
||||
been added to this datatype which provide just the numeric portion. See the JavaDoc
|
||||
for more information.
|
||||
</action>
|
||||
<action type="add">
|
||||
<![CDATA[<b>API CHANGE:</b>]]>: Most elements in the HAPI FHIR model contain
|
||||
a getId() and setId() method. This method is confusing because it is only actually used
|
||||
for IDREF elements (which are rare) but its name makes it easy to confuse with more
|
||||
important identifiers. For this reason, these methods have been deprocated and replaced with
|
||||
get/setElementSpecificId() methods. The old methods will be removed at some point. Resource
|
||||
types are unchanged and retain their get/setId methods.
|
||||
</action>
|
||||
<action type="add">
|
||||
Allow use of QuantityDt as a service parameter to support the "quantity" type. Previously
|
||||
QuantityDt did not implement IQueryParameterType so it was not valid, and there was no way to
|
||||
support quantity search parameters on the server (e.g. Observation.value-quantity)
|
||||
</action>
|
||||
<action type="add">
|
||||
Introduce StringParameter type which can be used as a RESTful operation search parameter
|
||||
type. StringParameter allows ":exact" matches to be specified in clients, and handled in servers.
|
||||
</action>
|
||||
<action type="add">
|
||||
Parsers (XML/JSON) now support deleted entries in bundles
|
||||
</action>
|
||||
<action type="add">
|
||||
Transaction method now supported in servers
|
||||
</action>
|
||||
<action type="add">
|
||||
Support for Binary resources added (in servers, clients, parsers, etc.)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Support for Query resources fixed (in parser)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Nested contained resources (e.g. encoding a resource with a contained resource that itself contains a resource)
|
||||
now parse and encode correctly, meaning that all contained resources are placed in the "contained" element
|
||||
of the root resource, and the parser looks in the root resource for all container levels when stitching
|
||||
contained resources back together.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server methods with @Include parameter would sometimes fail when no _include was actually
|
||||
specified in query strings.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Client requests for IdentifierDt types (such as Patient.identifier) did not create the correct
|
||||
query string if the system is null.
|
||||
</action>
|
||||
<action type="add">
|
||||
Add support for paging responses from RESTful servers.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Don't fail on narrative blocks in JSON resources with only an XML declaration but no content (these are
|
||||
produced by the Health Intersections server)
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server now automatically compresses responses if the client indicates support
|
||||
</action>
|
||||
<action type="fix">
|
||||
Server failed to support optional parameters when type is String and :exact qualifier is used
|
||||
</action>
|
||||
<action type="fix">
|
||||
Read method in client correctly populated resource ID in returned object
|
||||
</action>
|
||||
<action type="add">
|
||||
Support added for deleted-entry by/name, by/email, and comment from Tombstones spec
|
||||
</action>
|
||||
</release>
|
||||
<release version="0.3" date="2014-May-12" description="This release corrects lots of bugs and introduces the fluent client mode">
|
||||
</release>
|
||||
</body>
|
||||
</document>
|
Loading…
Reference in New Issue