[(master)] Added support for extensions in Meta resource
This commit is contained in:
parent
dea9cdde58
commit
53674db357
|
@ -613,5 +613,30 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
|||
public abstract void put(IAnyResource theResource, T2 theObject);
|
||||
|
||||
}
|
||||
|
||||
public static final class ExtensionResourceMetadataKey extends ResourceMetadataKeyEnum<ExtensionDt> {
|
||||
public ExtensionResourceMetadataKey(String url) {
|
||||
super(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionDt get(IResource theResource) {
|
||||
Object retValObj = theResource.getResourceMetadata().get(this);
|
||||
if (retValObj == null) {
|
||||
return null;
|
||||
} else if (retValObj instanceof ExtensionDt) {
|
||||
return (ExtensionDt) retValObj;
|
||||
}
|
||||
throw new InternalErrorException("Found an object of type '" + retValObj.getClass().getCanonicalName()
|
||||
+ "' in resource metadata for key " + this.name() + " - Expected "
|
||||
+ ExtensionDt.class.getCanonicalName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(IResource theResource, ExtensionDt theObject) {
|
||||
theResource.getResourceMetadata().put(this, theObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -911,6 +911,18 @@ public abstract class BaseParser implements IParser {
|
|||
throw new DataFormatException(nextChild + " has no child of type " + theType);
|
||||
}
|
||||
|
||||
protected List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> getExtensionMetadataKeys(IResource resource) {
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys = new ArrayList<Map.Entry<ResourceMetadataKeyEnum<?>, Object>>();
|
||||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> entry : resource.getResourceMetadata().entrySet()) {
|
||||
if (entry.getKey() instanceof ResourceMetadataKeyEnum.ExtensionResourceMetadataKey) {
|
||||
extensionMetadataKeys.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
return extensionMetadataKeys;
|
||||
}
|
||||
|
||||
|
||||
protected static <T> List<T> extractMetadataListNotNull(IResource resource, ResourceMetadataKeyEnum<List<T>> key) {
|
||||
List<? extends T> securityLabels = key.get(resource);
|
||||
if (securityLabels == null) {
|
||||
|
|
|
@ -650,8 +650,9 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
if (isBlank(versionIdPart)) {
|
||||
versionIdPart = ResourceMetadataKeyEnum.VERSION.get(resource);
|
||||
}
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys = getExtensionMetadataKeys(resource);
|
||||
|
||||
if (super.shouldEncodeResourceMeta(resource) && ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) {
|
||||
if (super.shouldEncodeResourceMeta(resource) && (ElementUtil.isEmpty(versionIdPart, updated, securityLabels, tags, profiles) == false) || !extensionMetadataKeys.isEmpty()) {
|
||||
beginObject(theEventWriter, "meta");
|
||||
writeOptionalTagWithTextNode(theEventWriter, "versionId", versionIdPart);
|
||||
writeOptionalTagWithTextNode(theEventWriter, "lastUpdated", updated);
|
||||
|
@ -691,6 +692,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
addExtensionMetadata(extensionMetadataKeys, theEventWriter);
|
||||
|
||||
theEventWriter.endObject(); // end meta
|
||||
}
|
||||
}
|
||||
|
@ -712,6 +715,41 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
|
|||
theEventWriter.endObject();
|
||||
}
|
||||
|
||||
private void addExtensionMetadata(List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionMetadataKeys, JsonLikeWriter theEventWriter) throws IOException {
|
||||
if (extensionMetadataKeys.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensionKeys = new ArrayList<>(extensionMetadataKeys.size());
|
||||
List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> modifierExtensionKeys = new ArrayList<>(extensionKeys.size());
|
||||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> entry : extensionMetadataKeys) {
|
||||
if (!((ExtensionDt) entry.getValue()).isModifier()) {
|
||||
extensionKeys.add(entry);
|
||||
} else {
|
||||
modifierExtensionKeys.add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
writeMetadataExtensions(extensionKeys, "extension", theEventWriter);
|
||||
writeMetadataExtensions(extensionKeys, "modifierExtension", theEventWriter);
|
||||
}
|
||||
|
||||
private void writeMetadataExtensions(List<Map.Entry<ResourceMetadataKeyEnum<?>, Object>> extensions, String arrayName, JsonLikeWriter theEventWriter) throws IOException {
|
||||
if (extensions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
beginArray(theEventWriter, arrayName);
|
||||
for (Map.Entry<ResourceMetadataKeyEnum<?>, Object> key : extensions) {
|
||||
ExtensionDt extension = (ExtensionDt) key.getValue();
|
||||
theEventWriter.beginObject();
|
||||
writeOptionalTagWithTextNode(theEventWriter, "url", extension.getUrl());
|
||||
String extensionDatatype = myContext.getRuntimeChildUndeclaredExtensionDefinition().getChildNameByDatatype(extension.getValue().getClass());
|
||||
writeOptionalTagWithTextNode(theEventWriter, extensionDatatype, extension.getValueAsPrimitive());
|
||||
theEventWriter.endObject();
|
||||
}
|
||||
theEventWriter.endArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is useful only for the two cases where extensions are encoded as direct children (e.g. not in some object
|
||||
* called _name): resource extensions, and extension extensions
|
||||
|
|
|
@ -841,6 +841,25 @@ class ParserState<T> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enteringNewElementExtension(StartElement theElem, String theUrlAttr, boolean theIsModifier, final String baseServerUrl) {
|
||||
ResourceMetadataKeyEnum.ExtensionResourceMetadataKey resourceMetadataKeyEnum = new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(theUrlAttr);
|
||||
Object metadataValue = myMap.get(resourceMetadataKeyEnum);
|
||||
ExtensionDt newExtension;
|
||||
if (metadataValue == null) {
|
||||
newExtension = new ExtensionDt(theIsModifier);
|
||||
} else if (metadataValue instanceof ExtensionDt) {
|
||||
newExtension = (ExtensionDt) metadataValue;
|
||||
} else {
|
||||
throw new IllegalStateException("Expected ExtensionDt as custom resource metadata type, got: " + metadataValue.getClass().getSimpleName());
|
||||
}
|
||||
newExtension.setUrl(theUrlAttr);
|
||||
myMap.put(resourceMetadataKeyEnum, newExtension);
|
||||
|
||||
ExtensionState newState = new ExtensionState(getPreResourceState(), newExtension);
|
||||
push(newState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class MetaVersionElementState extends BaseState {
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
@ -1688,19 +1690,65 @@ public class JsonParserDstu2Test {
|
|||
Patient p = parser.parseResource(Patient.class, input);
|
||||
|
||||
ArgumentCaptor<String> capt = ArgumentCaptor.forClass(String.class);
|
||||
verify(peh, times(4)).unknownElement(Mockito.isNull(IParseLocation.class), capt.capture());
|
||||
|
||||
//@formatter:off
|
||||
List<String> strings = capt.getAllValues();
|
||||
assertThat(strings, contains(
|
||||
"extension",
|
||||
"extension",
|
||||
"modifierExtension",
|
||||
"modifierExtension"
|
||||
));
|
||||
//@formatter:off
|
||||
|
||||
verify(peh, Mockito.never()).unknownElement(Mockito.isNull(IParseLocation.class), capt.capture());
|
||||
assertEquals("Smith", p.getName().get(0).getGiven().get(0).getValue());
|
||||
assertExtensionMetadata(p, "fhir-request-method", false, StringDt.class, "POST");
|
||||
assertExtensionMetadata(p, "fhir-request-uri", false, UriDt.class, "Patient");
|
||||
assertExtensionMetadata(p, "modified-fhir-request-method", true, StringDt.class, "POST");
|
||||
assertExtensionMetadata(p, "modified-fhir-request-uri", true, UriDt.class, "Patient");
|
||||
}
|
||||
|
||||
private void assertExtensionMetadata(
|
||||
BaseResource resource,
|
||||
String url,
|
||||
boolean isModifier,
|
||||
Class<?> expectedType,
|
||||
String expectedValue) {
|
||||
ExtensionDt extension = (ExtensionDt) resource.getResourceMetadata().get(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(url));
|
||||
assertThat(extension.getValue(), instanceOf(expectedType));
|
||||
assertThat(extension.isModifier(), equalTo(isModifier));
|
||||
assertThat(extension.getValueAsPrimitive().getValueAsString(), equalTo(expectedValue));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeResourceWithExtensionMetadata() throws Exception {
|
||||
ProcedureRequest procedureRequest = new ProcedureRequest();
|
||||
procedureRequest.setStatus(ProcedureRequestStatusEnum.ACCEPTED);
|
||||
addExtensionResourceMetadataKeyToResource(procedureRequest, false, "http://someurl.com", "SomeValue");
|
||||
addExtensionResourceMetadataKeyToResource(procedureRequest, false, "http://someurl2.com", "SomeValue2");
|
||||
addExtensionResourceMetadataKeyToResource(procedureRequest, true, "http://someurl.com/modifier", "SomeValue");
|
||||
addExtensionResourceMetadataKeyToResource(procedureRequest, true, "http://someurl.com/modifier2", "SomeValue2");
|
||||
|
||||
String json = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(procedureRequest);
|
||||
|
||||
// @formatter:off
|
||||
assertThat(json, stringContainsInOrder("\"meta\": {",
|
||||
"\"extension\": [", "{",
|
||||
"\"url\": \"http://someurl.com\",",
|
||||
"\"valueString\": \"SomeValue\"",
|
||||
"},",
|
||||
"{",
|
||||
"\"url\": \"http://someurl2.com\",",
|
||||
"\"valueString\": \"SomeValue2\"",
|
||||
"}",
|
||||
"],",
|
||||
"\"modifierExtension\": [",
|
||||
"{",
|
||||
"\"url\": \"http://someurl.com\",",
|
||||
"\"valueString\": \"SomeValue\"",
|
||||
"},",
|
||||
"{",
|
||||
"\"url\": \"http://someurl2.com\",",
|
||||
"\"valueString\": \"SomeValue2\"",
|
||||
"}",
|
||||
"]"));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private void addExtensionResourceMetadataKeyToResource(BaseResource resource, boolean isModifier, String url, String value) {
|
||||
ExtensionDt extensionDt = new ExtensionDt(isModifier, url, new StringDt(value));
|
||||
resource.getResourceMetadata()
|
||||
.put(new ResourceMetadataKeyEnum.ExtensionResourceMetadataKey(extensionDt.getUrl()), extensionDt);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -1,35 +1,35 @@
|
|||
{
|
||||
"id": "73b551fb-46f5-4fb8-b735-2399344e9717",
|
||||
"meta": {
|
||||
"extension": [
|
||||
{
|
||||
"url": "fhir-request-method",
|
||||
"valueString": "POST"
|
||||
},
|
||||
{
|
||||
"url": "fhir-request-uri",
|
||||
"valueUri": "Patient"
|
||||
}
|
||||
],
|
||||
"modifierExtension": [
|
||||
{
|
||||
"url": "fhir-request-method",
|
||||
"valueString": "POST"
|
||||
},
|
||||
{
|
||||
"url": "fhir-request-uri",
|
||||
"valueUri": "Patient"
|
||||
}
|
||||
],
|
||||
"versionId": "01e5253d-d258-494c-8d8e-f22ad6d8f19b",
|
||||
"lastUpdated": "2016-02-20T11:01:56.155Z"
|
||||
},
|
||||
"name": [
|
||||
{
|
||||
"given": [
|
||||
"Smith"
|
||||
]
|
||||
}
|
||||
],
|
||||
"resourceType": "Patient"
|
||||
}
|
||||
{
|
||||
"id": "73b551fb-46f5-4fb8-b735-2399344e9717",
|
||||
"meta": {
|
||||
"extension": [
|
||||
{
|
||||
"url": "fhir-request-method",
|
||||
"valueString": "POST"
|
||||
},
|
||||
{
|
||||
"url": "fhir-request-uri",
|
||||
"valueUri": "Patient"
|
||||
}
|
||||
],
|
||||
"modifierExtension": [
|
||||
{
|
||||
"url": "modified-fhir-request-method",
|
||||
"valueString": "POST"
|
||||
},
|
||||
{
|
||||
"url": "modified-fhir-request-uri",
|
||||
"valueUri": "Patient"
|
||||
}
|
||||
],
|
||||
"versionId": "01e5253d-d258-494c-8d8e-f22ad6d8f19b",
|
||||
"lastUpdated": "2016-02-20T11:01:56.155Z"
|
||||
},
|
||||
"name": [
|
||||
{
|
||||
"given": [
|
||||
"Smith"
|
||||
]
|
||||
}
|
||||
],
|
||||
"resourceType": "Patient"
|
||||
}
|
||||
|
|
|
@ -29,64 +29,73 @@ package org.hl7.fhir.dstu3.model.codesystems;
|
|||
|
||||
*/
|
||||
|
||||
// Generated on Mon, Jan 16, 2017 12:12-0500 for FHIR v1.9.0
|
||||
// Generated on Sat, Mar 25, 2017 21:03-0400 for FHIR v3.0.0
|
||||
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
||||
public enum Devicestatus {
|
||||
public enum DeviceStatus {
|
||||
|
||||
/**
|
||||
* The Device is available for use.
|
||||
* The Device is available for use. Note: This means for *implanted devices* the device is implanted in the patient.
|
||||
*/
|
||||
AVAILABLE,
|
||||
ACTIVE,
|
||||
/**
|
||||
* The Device is no longer available for use (e.g. lost, expired, damaged).
|
||||
* The Device is no longer available for use (e.g. lost, expired, damaged). Note: This means for *implanted devices* the device has been removed from the patient.
|
||||
*/
|
||||
NOTAVAILABLE,
|
||||
INACTIVE,
|
||||
/**
|
||||
* The Device was entered in error and voided.
|
||||
*/
|
||||
ENTEREDINERROR,
|
||||
/**
|
||||
* The status of the device has not been determined.
|
||||
*/
|
||||
UNKNOWN,
|
||||
/**
|
||||
* added to help the parsers
|
||||
*/
|
||||
NULL;
|
||||
public static Devicestatus fromCode(String codeString) throws FHIRException {
|
||||
public static DeviceStatus fromCode(String codeString) throws FHIRException {
|
||||
if (codeString == null || "".equals(codeString))
|
||||
return null;
|
||||
if ("available".equals(codeString))
|
||||
return AVAILABLE;
|
||||
if ("not-available".equals(codeString))
|
||||
return NOTAVAILABLE;
|
||||
if ("active".equals(codeString))
|
||||
return ACTIVE;
|
||||
if ("inactive".equals(codeString))
|
||||
return INACTIVE;
|
||||
if ("entered-in-error".equals(codeString))
|
||||
return ENTEREDINERROR;
|
||||
throw new FHIRException("Unknown Devicestatus code '"+codeString+"'");
|
||||
if ("unknown".equals(codeString))
|
||||
return UNKNOWN;
|
||||
throw new FHIRException("Unknown DeviceStatus code '"+codeString+"'");
|
||||
}
|
||||
public String toCode() {
|
||||
switch (this) {
|
||||
case AVAILABLE: return "available";
|
||||
case NOTAVAILABLE: return "not-available";
|
||||
case ACTIVE: return "active";
|
||||
case INACTIVE: return "inactive";
|
||||
case ENTEREDINERROR: return "entered-in-error";
|
||||
case UNKNOWN: return "unknown";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
public String getSystem() {
|
||||
return "http://hl7.org/fhir/devicestatus";
|
||||
return "http://hl7.org/fhir/device-status";
|
||||
}
|
||||
public String getDefinition() {
|
||||
switch (this) {
|
||||
case AVAILABLE: return "The Device is available for use.";
|
||||
case NOTAVAILABLE: return "The Device is no longer available for use (e.g. lost, expired, damaged).";
|
||||
case ACTIVE: return "The Device is available for use. Note: This means for *implanted devices* the device is implanted in the patient.";
|
||||
case INACTIVE: return "The Device is no longer available for use (e.g. lost, expired, damaged). Note: This means for *implanted devices* the device has been removed from the patient.";
|
||||
case ENTEREDINERROR: return "The Device was entered in error and voided.";
|
||||
case UNKNOWN: return "The status of the device has not been determined.";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
public String getDisplay() {
|
||||
switch (this) {
|
||||
case AVAILABLE: return "Available";
|
||||
case NOTAVAILABLE: return "Not Available";
|
||||
case ACTIVE: return "Active";
|
||||
case INACTIVE: return "Inactive";
|
||||
case ENTEREDINERROR: return "Entered in Error";
|
||||
case UNKNOWN: return "Unknown";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,36 +29,40 @@ package org.hl7.fhir.dstu3.model.codesystems;
|
|||
|
||||
*/
|
||||
|
||||
// Generated on Mon, Jan 16, 2017 12:12-0500 for FHIR v1.9.0
|
||||
// Generated on Sat, Mar 25, 2017 21:03-0400 for FHIR v3.0.0
|
||||
|
||||
|
||||
import org.hl7.fhir.dstu3.model.EnumFactory;
|
||||
|
||||
public class DevicestatusEnumFactory implements EnumFactory<Devicestatus> {
|
||||
public class DeviceStatusEnumFactory implements EnumFactory<DeviceStatus> {
|
||||
|
||||
public Devicestatus fromCode(String codeString) throws IllegalArgumentException {
|
||||
public DeviceStatus fromCode(String codeString) throws IllegalArgumentException {
|
||||
if (codeString == null || "".equals(codeString))
|
||||
return null;
|
||||
if ("available".equals(codeString))
|
||||
return Devicestatus.AVAILABLE;
|
||||
if ("not-available".equals(codeString))
|
||||
return Devicestatus.NOTAVAILABLE;
|
||||
if ("active".equals(codeString))
|
||||
return DeviceStatus.ACTIVE;
|
||||
if ("inactive".equals(codeString))
|
||||
return DeviceStatus.INACTIVE;
|
||||
if ("entered-in-error".equals(codeString))
|
||||
return Devicestatus.ENTEREDINERROR;
|
||||
throw new IllegalArgumentException("Unknown Devicestatus code '"+codeString+"'");
|
||||
return DeviceStatus.ENTEREDINERROR;
|
||||
if ("unknown".equals(codeString))
|
||||
return DeviceStatus.UNKNOWN;
|
||||
throw new IllegalArgumentException("Unknown DeviceStatus code '"+codeString+"'");
|
||||
}
|
||||
|
||||
public String toCode(Devicestatus code) {
|
||||
if (code == Devicestatus.AVAILABLE)
|
||||
return "available";
|
||||
if (code == Devicestatus.NOTAVAILABLE)
|
||||
return "not-available";
|
||||
if (code == Devicestatus.ENTEREDINERROR)
|
||||
public String toCode(DeviceStatus code) {
|
||||
if (code == DeviceStatus.ACTIVE)
|
||||
return "active";
|
||||
if (code == DeviceStatus.INACTIVE)
|
||||
return "inactive";
|
||||
if (code == DeviceStatus.ENTEREDINERROR)
|
||||
return "entered-in-error";
|
||||
if (code == DeviceStatus.UNKNOWN)
|
||||
return "unknown";
|
||||
return "?";
|
||||
}
|
||||
|
||||
public String toSystem(Devicestatus code) {
|
||||
public String toSystem(DeviceStatus code) {
|
||||
return code.getSystem();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue