diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtils.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtils.java deleted file mode 100644 index 97d65a3194d..00000000000 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtils.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * #%L - * HAPI FHIR JPA Server - * %% - * Copyright (C) 2014 - 2024 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.jpa.util.jsonpatch; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.parser.DataFormatException; -import ca.uhn.fhir.parser.IParser; -import ca.uhn.fhir.parser.StrictErrorHandler; -import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.fge.jsonpatch.JsonPatch; -import com.github.fge.jsonpatch.JsonPatchException; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.intellij.lang.annotations.Language; - -import java.io.IOException; - -import static org.apache.commons.lang3.StringUtils.defaultString; - -public class JsonPatchUtils { - - public static T apply( - FhirContext theCtx, T theResourceToUpdate, @Language("JSON") String thePatchBody) { - // Parse the patch - ObjectMapper mapper = new ObjectMapper(); - mapper.configure(JsonParser.Feature.INCLUDE_SOURCE_IN_LOCATION, false); - - JsonFactory factory = mapper.getFactory(); - - final JsonPatch patch; - try { - com.fasterxml.jackson.core.JsonParser parser = factory.createParser(thePatchBody); - JsonNode jsonPatchNode = mapper.readTree(parser); - patch = JsonPatch.fromJson(jsonPatchNode); - - JsonNode originalJsonDocument = - mapper.readTree(theCtx.newJsonParser().encodeResourceToString(theResourceToUpdate)); - JsonNode after = patch.apply(originalJsonDocument); - - @SuppressWarnings("unchecked") - Class clazz = (Class) theResourceToUpdate.getClass(); - - String postPatchedContent = mapper.writeValueAsString(after); - - IParser fhirJsonParser = theCtx.newJsonParser(); - fhirJsonParser.setParserErrorHandler(new StrictErrorHandler()); - - T retVal; - try { - retVal = fhirJsonParser.parseResource(clazz, postPatchedContent); - } catch (DataFormatException e) { - String resourceId = theResourceToUpdate - .getIdElement() - .toUnqualifiedVersionless() - .getValue(); - String resourceType = theCtx.getResourceType(theResourceToUpdate); - resourceId = defaultString(resourceId, resourceType); - String msg = theCtx.getLocalizer() - .getMessage(JsonPatchUtils.class, "failedToApplyPatch", resourceId, e.getMessage()); - throw new InvalidRequestException(Msg.code(818) + msg); - } - return retVal; - - } catch (IOException | JsonPatchException theE) { - throw new InvalidRequestException(Msg.code(819) + theE.getMessage()); - } - } -} diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java index 806fb9a8c9b..e3c29091f6d 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java @@ -4,7 +4,10 @@ import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.test.config.TestR4Config; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; +import ca.uhn.fhir.util.BundleBuilder; import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -15,6 +18,7 @@ import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Bundle.HTTPVerb; import org.hl7.fhir.r4.model.CarePlan; import org.hl7.fhir.r4.model.Condition; +import org.hl7.fhir.r4.model.ContactPoint; import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Parameters; @@ -26,6 +30,7 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; @@ -68,6 +73,36 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { myStorageSettings.setBundleBatchMaxPoolSize(JpaStorageSettings.DEFAULT_BUNDLE_BATCH_MAX_POOL_SIZE); } + + @Test + public void testPatchInTransactionBundleSupportsIfMatchTag() { + Patient newPatient = new Patient(); + newPatient.setId("my-patient"); + newPatient.getTelecomFirstRep().setSystem(ContactPoint.ContactPointSystem.PHONE).setValue("123-456-7890"); + myClient.update().resource(newPatient).execute(); + String bundleString = "{\n" + + "\t\"resourceType\": \"Bundle\",\n" + + "\t\"type\": \"transaction\",\n" + + "\t\"entry\": [{\n" + + "\t\t\"fullUrl\": \"Patient/my-patient\",\n" + + "\t\t\"resource\": {\n" + + "\t\t\t\"resourceType\": \"Binary\",\n" + + "\t\t\t\"contentType\": \"application/json-patch+json\",\n" + + "\t\t\t\"data\": \"W3sib3AiOiJyZXBsYWNlIiwicGF0aCI6IlwvdGVsZWNvbVwvMFwvdmFsdWUiLCJ2YWx1ZSI6IjQwMTEyMzQ1NiJ9XQ==\"\n" + + "\t\t},\n" + + "\t\t\"request\": {\n" + + "\t\t\t\"method\": \"PATCH\",\n" + + "\t\t\t\"url\": \"Patient/my-patient\",\n" + + "\t\t\t\"ifMatch\": \"W/\\\"1\\\"\"\n" + + "\t\t}\n" + + "\t}]\n" + + "}"; + Bundle bundle = myFhirContext.newJsonParser().parseResource(Bundle.class, bundleString); + myClient.transaction().withBundle(bundle).execute(); + Patient execute1 = myClient.read().resource(Patient.class).withId("my-patient").execute(); + assertThat(execute1).extracting(p -> p.getTelecomFirstRep().getValue()).isEqualTo("401123456"); + } + /** * See #401 */