diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java index a2f335130e9..3b2e929ce6f 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/composite/BaseCodingDt.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.model.api.BaseIdentifiableElement; import ca.uhn.fhir.model.api.ICompositeDatatype; import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.model.primitive.BooleanDt; import ca.uhn.fhir.model.primitive.CodeDt; import ca.uhn.fhir.model.primitive.StringDt; import ca.uhn.fhir.model.primitive.UriDt; @@ -58,6 +59,10 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC */ public abstract UriDt getSystemElement(); + public abstract StringDt getVersionElement(); + + public abstract BooleanDt getUserSelectedElement(); + /** * Gets the value(s) for display (Representation defined by the system). * creating it if it does @@ -72,13 +77,6 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC public abstract BaseCodingDt setDisplay(String theString); - /* - todo: handle version - public abstract StringDt getVersion(); - - public abstract BaseCodingDt setVersion ( String theString); - */ - /** * {@inheritDoc} */ @@ -181,7 +179,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC * @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you * need this functionality */ - @Deprecated + @Deprecated(since = "6.0.0") @Override public Boolean getMissing() { return null; @@ -193,7 +191,7 @@ public abstract class BaseCodingDt extends BaseIdentifiableElement implements IC * @deprecated get/setMissing is not supported in StringDt. Use {@link TokenParam} instead if you * need this functionality */ - @Deprecated + @Deprecated(since = "6.0.0") @Override public IQueryParameterType setMissing(Boolean theMissing) { throw new UnsupportedOperationException( diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java index 6f51c24e136..846d5dab271 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java @@ -1033,7 +1033,8 @@ public class JsonParser extends BaseParser implements IJsonLikeParser { writeOptionalTagWithTextNode(theEventWriter, "system", tag.getScheme()); writeOptionalTagWithTextNode(theEventWriter, "code", tag.getTerm()); writeOptionalTagWithTextNode(theEventWriter, "display", tag.getLabel()); - // wipmb should we be writing the new properties here? There must be another path. + writeOptionalTagWithTextNode(theEventWriter, "version", tag.getVersion()); + write(theEventWriter, "userSelected", tag.getUserSelectedBoolean()); theEventWriter.endObject(); } theEventWriter.endArray(); diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java index 4ebe4b3ea62..c25a3d11984 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java @@ -636,7 +636,7 @@ class ParserState { BaseRuntimeElementDefinition target = child.getChildByName(theChildName); if (target == null) { - // This is a bug with the structures and shouldn't happen.. + // This is a bug with the structures and shouldn't happen. throw new DataFormatException( Msg.code(1809) + "Found unexpected element '" + theChildName + "' in parent element '" + myDefinition.getName() + "'. Valid names are: " + child.getValidChildNames()); @@ -1584,16 +1584,20 @@ class ParserState { private class TagState extends BaseState { - private static final int LABEL = 2; private static final int NONE = 0; + private static final int TERM = 1; + private static final int LABEL = 2; private static final int SCHEME = 3; - private static final int TERM = 1; + private static final int VERSION = 4; + private static final int USER_SELECTED = 5; private String myLabel; private String myScheme; private int mySubState = 0; private TagList myTagList; private String myTerm; + private String myVersion; + private Boolean myUserSelected; public TagState(TagList theTagList) { super(null); @@ -1614,6 +1618,12 @@ class ParserState { case SCHEME: myScheme = (value); break; + case VERSION: + myVersion = (value); + break; + case USER_SELECTED: + myUserSelected = Boolean.valueOf(value); + break; case NONE: // This handles JSON encoding, which is a bit weird enteringNewElement(null, theName); @@ -1629,7 +1639,9 @@ class ParserState { mySubState = NONE; } else { if (isNotEmpty(myScheme) || isNotBlank(myTerm) || isNotBlank(myLabel)) { - myTagList.addTag(myScheme, myTerm, myLabel); + Tag tag = myTagList.addTag(myScheme, myTerm, myLabel); + tag.setUserSelectedBoolean(myUserSelected); + tag.setVersion(myVersion); } pop(); } @@ -1646,6 +1658,10 @@ class ParserState { mySubState = SCHEME; } else if (Tag.ATTR_LABEL.equals(theLocalPart) || "display".equals(theLocalPart)) { mySubState = LABEL; + } else if ("userSelected".equals(theLocalPart)) { + mySubState = USER_SELECTED; + } else if ("version".equals(theLocalPart)) { + mySubState = VERSION; } else { throw new DataFormatException(Msg.code(1818) + "Unexpected element: " + theLocalPart); } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java index fba60711839..94f330c9416 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/XmlParser.java @@ -187,7 +187,8 @@ public class XmlParser extends BaseParser { String namespaceURI = elem.getName().getNamespaceURI(); - if ("extension".equals(elem.getName().getLocalPart())) { + String localPart = elem.getName().getLocalPart(); + if ("extension".equals(localPart)) { Attribute urlAttr = elem.getAttributeByName(new QName("url")); String url; if (urlAttr == null || isBlank(urlAttr.getValue())) { @@ -199,7 +200,7 @@ public class XmlParser extends BaseParser { url = urlAttr.getValue(); } parserState.enteringNewElementExtension(elem, url, false, getServerBaseUrl()); - } else if ("modifierExtension".equals(elem.getName().getLocalPart())) { + } else if ("modifierExtension".equals(localPart)) { Attribute urlAttr = elem.getAttributeByName(new QName("url")); String url; if (urlAttr == null || isBlank(urlAttr.getValue())) { @@ -213,8 +214,7 @@ public class XmlParser extends BaseParser { } parserState.enteringNewElementExtension(elem, url, true, getServerBaseUrl()); } else { - String elementName = elem.getName().getLocalPart(); - parserState.enteringNewElement(namespaceURI, elementName); + parserState.enteringNewElement(namespaceURI, localPart); } if (!heldComments.isEmpty()) { @@ -768,6 +768,11 @@ public class XmlParser extends BaseParser { writeOptionalTagWithValue(theEventWriter, "system", tag.getScheme()); writeOptionalTagWithValue(theEventWriter, "code", tag.getTerm()); writeOptionalTagWithValue(theEventWriter, "display", tag.getLabel()); + writeOptionalTagWithValue(theEventWriter, "version", tag.getVersion()); + Boolean userSelected = tag.getUserSelectedBoolean(); + if (userSelected != null) { + writeOptionalTagWithValue(theEventWriter, "userSelected", userSelected.toString()); + } theEventWriter.writeEndElement(); } } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java index 49be6fd8040..393e5cb8562 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/param/InternalCodingDt.java @@ -151,13 +151,27 @@ public class InternalCodingDt extends BaseCodingDt implements ICompositeDatatype * is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged *

*/ - public StringDt getVersion() { + @Override + public StringDt getVersionElement() { if (myVersion == null) { myVersion = new StringDt(); } return myVersion; } + @Override + public BooleanDt getUserSelectedElement() { + return new BooleanDt(); + } + + /** + * Legacy name for {@link #getVersionElement()} + */ + @Deprecated(since = "7.0.0") + public StringDt getVersion() { + return getVersionElement(); + } + /** * Sets the value(s) for version (Version of the system - if relevant) * diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5310-broken-tag-parse.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5310-broken-tag-parse.yaml new file mode 100644 index 00000000000..1b647288093 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5310-broken-tag-parse.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5310 +title: "Update DSTU2 tags and security labels with support for `userSelected` and `version` elements. + Also fix them on security labels in JPA storage." diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index a4e867acddd..33eeec813b5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -32,7 +32,6 @@ import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.model.RequestPartitionId; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.IDao; import ca.uhn.fhir.jpa.api.dao.IJpaDao; import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; @@ -137,6 +136,7 @@ import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionTemplate; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -227,9 +227,6 @@ public abstract class BaseHapiFhirDao extends BaseStora @Autowired protected IInterceptorBroadcaster myInterceptorBroadcaster; - @Autowired - protected DaoRegistry myDaoRegistry; - @Autowired protected InMemoryResourceMatcher myInMemoryResourceMatcher; @@ -336,8 +333,8 @@ public abstract class BaseHapiFhirDao extends BaseStora next.getSystemElement().getValue(), next.getCodeElement().getValue(), next.getDisplayElement().getValue(), - null, - null); + next.getVersionElement().getValue(), + next.getUserSelectedElement().getValue()); if (def != null) { ResourceTag tag = theEntity.addTag(def); allDefs.add(tag); @@ -566,11 +563,9 @@ public abstract class BaseHapiFhirDao extends BaseStora } }); } catch (Exception ex) { - // transaction template can fail if connections to db are exhausted - // and/or timeout - ourLog.warn("Transaction failed with: " - + ex.getMessage() + ". " - + "Transaction will rollback and be reattempted."); + // transaction template can fail if connections to db are exhausted and/or timeout + ourLog.warn( + "Transaction failed with: {}. Transaction will rollback and be reattempted.", ex.getMessage()); retVal = null; } count++; @@ -700,7 +695,7 @@ public abstract class BaseHapiFhirDao extends BaseStora } String hashSha256 = hashCode.toString(); - if (hashSha256.equals(theEntity.getHashSha256()) == false) { + if (!hashSha256.equals(theEntity.getHashSha256())) { changed = true; } theEntity.setHashSha256(hashSha256); @@ -784,7 +779,7 @@ public abstract class BaseHapiFhirDao extends BaseStora byte[] resourceBinary; switch (encoding) { case JSON: - resourceBinary = encodedResource.getBytes(Charsets.UTF_8); + resourceBinary = encodedResource.getBytes(StandardCharsets.UTF_8); break; case JSONC: resourceBinary = GZipUtil.compress(encodedResource); @@ -1592,7 +1587,7 @@ public abstract class BaseHapiFhirDao extends BaseStora if (!thePerformIndexing && !savedEntity.isUnchangedInCurrentOperation() && !ourDisableIncrementOnUpdateForUnitTest) { - if (theResourceId.hasVersionIdPart() == false) { + if (!theResourceId.hasVersionIdPart()) { theResourceId = theResourceId.withVersion(Long.toString(savedEntity.getVersion())); } incrementId(theResource, savedEntity, theResourceId); @@ -1673,11 +1668,9 @@ public abstract class BaseHapiFhirDao extends BaseStora protected void addPidToResource(IResourceLookup theEntity, IBaseResource theResource) { if (theResource instanceof IAnyResource) { - IDao.RESOURCE_PID.put( - (IAnyResource) theResource, theEntity.getPersistentId().getId()); + IDao.RESOURCE_PID.put(theResource, theEntity.getPersistentId().getId()); } else if (theResource instanceof IResource) { - IDao.RESOURCE_PID.put( - (IResource) theResource, theEntity.getPersistentId().getId()); + IDao.RESOURCE_PID.put(theResource, theEntity.getPersistentId().getId()); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java index f27601f5ca7..74ed3f1b492 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/JpaStorageResourceParser.java @@ -401,11 +401,14 @@ public class JpaStorageResourceParser implements IJpaStorageResourceParser { secLabel.setSystem(nextTag.getSystem()); secLabel.setCode(nextTag.getCode()); secLabel.setDisplay(nextTag.getDisplay()); - // wipmb these technically support userSelected and version + secLabel.setVersion(nextTag.getVersion()); + Boolean userSelected = nextTag.getUserSelected(); + if (userSelected != null) { + secLabel.setUserSelected(userSelected); + } securityLabels.add(secLabel); break; case TAG: - // wipmb check xml, etc. Tag e = new Tag(nextTag.getSystem(), nextTag.getCode(), nextTag.getDisplay()); e.setVersion(nextTag.getVersion()); // careful! These are Boolean, not boolean. diff --git a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ParseTest.java b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ParseTest.java new file mode 100644 index 00000000000..5a4a9afde60 --- /dev/null +++ b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ParseTest.java @@ -0,0 +1,70 @@ +package ca.uhn.fhir.jpa.dao.dstu2; + +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import org.hl7.fhir.instance.model.api.IBaseCoding; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class FhirResourceDaoDstu2ParseTest extends BaseJpaDstu2Test { + @Autowired + DaoRegistry myDaoRegistry; + + @Test + void testTagRoundTrip() { + // given + Patient resource = new Patient(); + IBaseCoding tag = resource.getMeta().addTag(); + tag.setCode("code"); + tag.setDisplay("display"); + tag.setSystem("oid:123"); + tag.setVersion("v1"); + tag.setUserSelected(true); + + // when + DaoMethodOutcome daoMethodOutcome = myPatientDao.create(resource, mySrd); + Patient resourceOut = myPatientDao.read(daoMethodOutcome.getId(), mySrd); + + // then + List tags = resourceOut.getMeta().getTag(); + assertEquals(1, tags.size(), "tag is present"); + IBaseCoding tagOut = tags.get(0); + assertEquals("code", tagOut.getCode()); + assertEquals("display", tagOut.getDisplay()); + assertEquals("oid:123", tagOut.getSystem()); + assertEquals("v1", tagOut.getVersion()); + assertEquals(true, tagOut.getUserSelected()); + } + + + @Test + void testSecurityRoundTrip() { + // given + Patient resource = new Patient(); + IBaseCoding coding = resource.getMeta().addSecurity(); + coding.setCode("code"); + coding.setDisplay("display"); + coding.setSystem("oid:123"); + coding.setVersion("v1"); + coding.setUserSelected(true); + + // when + DaoMethodOutcome daoMethodOutcome = myPatientDao.create(resource, mySrd); + Patient resourceOut = myPatientDao.read(daoMethodOutcome.getId(), mySrd); + + // then + List tags = resourceOut.getMeta().getSecurity(); + assertEquals(1, tags.size(), "coding is present"); + IBaseCoding codingOut = tags.get(0); + assertEquals("code", codingOut.getCode()); + assertEquals("display", codingOut.getDisplay()); + assertEquals("oid:123", codingOut.getSystem()); + assertEquals("v1", codingOut.getVersion()); + assertEquals(true, codingOut.getUserSelected()); + } +} diff --git a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java index 2256c351d97..625addbd379 100644 --- a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java +++ b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java @@ -22,6 +22,7 @@ package ca.uhn.fhir.storage.test; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.test.utilities.ITestDataBuilder; import com.google.common.collect.HashMultimap; @@ -47,10 +48,10 @@ public class DaoTestDataBuilder implements ITestDataBuilder.WithSupport, ITestDa final FhirContext myFhirCtx; final DaoRegistry myDaoRegistry; - SystemRequestDetails mySrd; + RequestDetails mySrd; final SetMultimap myIds = HashMultimap.create(); - public DaoTestDataBuilder(FhirContext theFhirCtx, DaoRegistry theDaoRegistry, SystemRequestDetails theSrd) { + public DaoTestDataBuilder(FhirContext theFhirCtx, DaoRegistry theDaoRegistry, RequestDetails theSrd) { myFhirCtx = theFhirCtx; myDaoRegistry = theDaoRegistry; mySrd = theSrd; diff --git a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java index cbcf3e11944..e9c96776b61 100644 --- a/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java +++ b/hapi-fhir-structures-dstu2/src/main/java/ca/uhn/fhir/model/dstu2/resource/BaseResource.java @@ -134,7 +134,7 @@ public abstract class BaseResource extends BaseElement implements IResource { public IBaseCoding addSecurity() { List tagList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this); if (tagList == null) { - tagList = new ArrayList(); + tagList = new ArrayList<>(); ResourceMetadataKeyEnum.SECURITY_LABELS.put(BaseResource.this, tagList); } CodingDt tag = new CodingDt(); @@ -185,7 +185,7 @@ public abstract class BaseResource extends BaseElement implements IResource { @Override public List> getProfile() { - ArrayList> retVal = new ArrayList>(); + ArrayList> retVal = new ArrayList<>(); List profilesList = ResourceMetadataKeyEnum.PROFILES.get(BaseResource.this); if (profilesList == null) { return Collections.emptyList(); @@ -198,16 +198,19 @@ public abstract class BaseResource extends BaseElement implements IResource { @Override public List getSecurity() { - ArrayList retVal = new ArrayList(); + ArrayList retVal = new ArrayList<>(); List labelsList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(BaseResource.this); if (labelsList == null) { return Collections.emptyList(); } for (BaseCodingDt next : labelsList) { - retVal.add(new CodingDt( - next.getSystemElement().getValue(), - next.getCodeElement().getValue()) - .setDisplay(next.getDisplayElement().getValue())); + CodingDt c = new CodingDt( + next.getSystemElement().getValue(), + next.getCodeElement().getValue()); + c.setDisplay(next.getDisplayElement().getValue()); + c.setUserSelected(next.getUserSelectedElement()); + c.setVersion(next.getVersionElement()); + retVal.add(c); } return retVal; } @@ -224,7 +227,7 @@ public abstract class BaseResource extends BaseElement implements IResource { @Override public List getTag() { - ArrayList retVal = new ArrayList(); + ArrayList retVal = new ArrayList<>(); TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(BaseResource.this); if (tagList == null) { return Collections.emptyList(); diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/dstu2/ModelParseTest.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/dstu2/ModelParseTest.java new file mode 100644 index 00000000000..7deff3c1a9f --- /dev/null +++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/model/dstu2/ModelParseTest.java @@ -0,0 +1,84 @@ +package ca.uhn.fhir.model.dstu2; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu2.resource.Bundle; +import ca.uhn.fhir.model.dstu2.resource.Patient; +import ca.uhn.fhir.parser.IParser; +import org.hl7.fhir.instance.model.api.IBaseCoding; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ModelParseTest { + static final Logger ourLog = LoggerFactory.getLogger(ModelParseTest.class); + static FhirContext ourFhirContext = FhirContext.forDstu2Cached(); + + @ParameterizedTest + @MethodSource("getParsers") + void testTagRoundTrip(IParser theParser) { + // given + Patient resource = new Patient(); + IBaseCoding tag = resource.getMeta().addTag(); + tag.setCode("code"); + tag.setDisplay("display"); + tag.setSystem("oid:123"); + tag.setVersion("v1"); + tag.setUserSelected(true); + + // when + String string = theParser.encodeResourceToString(resource); + ourLog.info("encoded: {}", string); + Patient bundleOut = theParser.parseResource(Patient.class, string); + + // then + List tags = bundleOut.getMeta().getTag(); + assertEquals(1, tags.size(), "tag is present"); + IBaseCoding tagOut = tags.get(0); + assertEquals("code", tagOut.getCode()); + assertEquals("display", tagOut.getDisplay()); + assertEquals("oid:123", tagOut.getSystem()); + assertEquals("v1", tagOut.getVersion()); + assertEquals(true, tagOut.getUserSelected()); + } + + @ParameterizedTest + @MethodSource("getParsers") + void testSecurityRoundTrip(IParser theParser) { + // given + Patient resource = new Patient(); + IBaseCoding coding = resource.getMeta().addSecurity(); + coding.setCode("code"); + coding.setDisplay("display"); + coding.setSystem("oid:123"); + coding.setVersion("v1"); + coding.setUserSelected(true); + + // when + String string = theParser.encodeResourceToString(resource); + ourLog.info("encoded: {}", string); + Patient bundleOut = theParser.parseResource(Patient.class, string); + + // then + List labels = bundleOut.getMeta().getSecurity(); + assertEquals(1, labels.size(), "security is present"); + IBaseCoding codingOut = labels.get(0); + assertEquals("code", codingOut.getCode()); + assertEquals("display", codingOut.getDisplay()); + assertEquals("oid:123", codingOut.getSystem()); + assertEquals("v1", codingOut.getVersion()); + assertEquals(true, codingOut.getUserSelected()); + } + + public static List getParsers() { + return List.of( + ourFhirContext.newJsonParser(), + // ourFhirContext.newRDFParser(), dstu2 doesn't support RDF + ourFhirContext.newXmlParser() + ); + } +} diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java index 7467eecc2d8..0a84a443a57 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ITestDataBuilder.java @@ -27,6 +27,7 @@ import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.MetaUtil; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseCoding; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.ICompositeType; @@ -182,8 +183,11 @@ public interface ITestDataBuilder { return t -> ((IBaseResource)t).setId(theId.toUnqualifiedVersionless()); } - default ICreationArgument withTag(String theSystem, String theCode) { - return t -> ((IBaseResource)t).getMeta().addTag().setSystem(theSystem).setCode(theCode); + default ICreationArgument withTag(String theSystem, String theCode, Consumer... theModifiers) { + return t -> { + IBaseCoding coding = ((IBaseResource) t).getMeta().addTag().setSystem(theSystem).setCode(theCode); + applyElementModifiers(coding, theModifiers); + }; } default ICreationArgument withSecurity(String theSystem, String theCode) {