From cc92bd7b0708754cfca2438aae86b49cb0c7aba5 Mon Sep 17 00:00:00 2001
From: jamesagnew
Date: Sun, 17 May 2020 11:56:50 -0400
Subject: [PATCH] Revert "Start working on FHIRPatch"
This reverts commit b3f6e7d521c1451186fb180db6d8538e9f5dfcd8.
---
.../BaseRuntimeDeclaredChildDefinition.java | 3 -
.../ca/uhn/fhir/rest/api/PatchTypeEnum.java | 30 +-
.../java/ca/uhn/fhir/rest/gclient/IPatch.java | 14 +-
.../java/ca/uhn/fhir/util/FhirTerser.java | 107 +-
.../java/ca/uhn/fhir/util/ParametersUtil.java | 92 +-
.../main/java/ca/uhn/fhir/util/XmlUtil.java | 50 +-
.../ca/uhn/fhir/i18n/hapi-messages.properties | 6 +-
.../fhir/rest/client/impl/GenericClient.java | 10 -
.../hapi/fhir/docs/GenericClientExample.java | 1018 ++++++++---------
.../hapi/fhir/docs/client/generic_client.md | 16 -
hapi-fhir-jpaserver-base/pom.xml | 5 -
.../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 25 +-
.../java/ca/uhn/fhir/jpa/patch/FhirPatch.java | 316 -----
.../jsonpatch}/JsonPatchUtils.java | 2 +-
.../xmlpatch}/XmlPatchUtils.java | 2 +-
.../fhir/jpa/patch/BaseFhirPatchCoreTest.java | 115 --
.../fhir/jpa/patch/FhirPatchR4CoreTest.java | 33 -
.../uhn/fhir/jpa/patch/FhirPatchR4Test.java | 330 ------
.../fhir/jpa/patch/FhirPatchR5CoreTest.java | 33 -
.../jpa/provider/r4/PatchProviderR4Test.java | 35 -
.../util/jsonpatch/JsonPatchUtilsTest.java | 1 -
.../server/method/PatchTypeParameter.java | 9 -
pom.xml | 5 -
23 files changed, 544 insertions(+), 1713 deletions(-)
delete mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/FhirPatch.java
rename hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/{patch => util/jsonpatch}/JsonPatchUtils.java (98%)
rename hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/{patch => util/xmlpatch}/XmlPatchUtils.java (97%)
delete mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/BaseFhirPatchCoreTest.java
delete mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4CoreTest.java
delete mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4Test.java
delete mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR5CoreTest.java
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java
index 9e19c01a896..eb667e765f9 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/BaseRuntimeDeclaredChildDefinition.java
@@ -164,9 +164,6 @@ public abstract class BaseRuntimeDeclaredChildDefinition extends BaseRuntimeChil
}
if (theClear) {
existingList.clear();
- if (theValue == null) {
- return;
- }
}
existingList.add(theValue);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/PatchTypeEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/PatchTypeEnum.java
index bd5ef3250ff..4e6d843496e 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/PatchTypeEnum.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/PatchTypeEnum.java
@@ -24,21 +24,14 @@ import ca.uhn.fhir.rest.annotation.Patch;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.util.UrlUtil;
-import javax.annotation.Nonnull;
-import java.util.HashMap;
-import java.util.Map;
-
/**
* Parameter type for methods annotated with {@link Patch}
*/
public enum PatchTypeEnum {
JSON_PATCH(Constants.CT_JSON_PATCH),
- XML_PATCH(Constants.CT_XML_PATCH),
- FHIR_PATCH_JSON(Constants.CT_FHIR_JSON_NEW),
- FHIR_PATCH_XML(Constants.CT_FHIR_XML_NEW);
+ XML_PATCH(Constants.CT_XML_PATCH);
- private static volatile Map ourContentTypeToPatchType;
private final String myContentType;
PatchTypeEnum(String theContentType) {
@@ -49,7 +42,6 @@ public enum PatchTypeEnum {
return myContentType;
}
- @Nonnull
public static PatchTypeEnum forContentTypeOrThrowInvalidRequestException(String theContentType) {
String contentType = theContentType;
int semiColonIdx = contentType.indexOf(';');
@@ -57,22 +49,12 @@ public enum PatchTypeEnum {
contentType = theContentType.substring(0, semiColonIdx);
}
contentType = contentType.trim();
-
-
- Map map = ourContentTypeToPatchType;
- if (map == null) {
- map = new HashMap<>();
- for (PatchTypeEnum next : values()) {
- map.put(next.getContentType(), next);
- }
- ourContentTypeToPatchType = map;
- }
-
- PatchTypeEnum retVal = map.get(contentType);
- if (retVal == null) {
+ if (Constants.CT_JSON_PATCH.equals(contentType)) {
+ return JSON_PATCH;
+ } else if (Constants.CT_XML_PATCH.equals(contentType)) {
+ return XML_PATCH;
+ } else {
throw new InvalidRequestException("Invalid Content-Type for PATCH operation: " + UrlUtil.sanitizeUrlPart(theContentType));
}
-
- return retVal;
}
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/IPatch.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/IPatch.java
index 4f4690a3929..d87eeb94cf8 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/IPatch.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/gclient/IPatch.java
@@ -20,23 +20,15 @@ package ca.uhn.fhir.rest.gclient;
* #L%
*/
-import org.hl7.fhir.instance.model.api.IBaseParameters;
-
public interface IPatch {
/**
* The body of the patch document serialized in either XML or JSON which conforms to
* http://jsonpatch.com/ or http://tools.ietf.org/html/rfc5261
- *
- * @param thePatchBody The body of the patch
+ *
+ * @param thePatchBody
+ * The body of the patch
*/
IPatchWithBody withBody(String thePatchBody);
- /**
- * The body of the patch document using FHIR Patch syntax as described at
- * http://hl7.org/fhir/fhirpatch.html
- *
- * @since 5.1.0
- */
- IPatchWithBody withFhirPatch(IBaseParameters thePatchBody);
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
index d5a47c3909a..786b92afd43 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/FhirTerser.java
@@ -1,17 +1,7 @@
package ca.uhn.fhir.util;
-import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
-import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
-import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
+import ca.uhn.fhir.context.*;
import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum;
-import ca.uhn.fhir.context.ConfigurationException;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.context.FhirVersionEnum;
-import ca.uhn.fhir.context.RuntimeChildChoiceDefinition;
-import ca.uhn.fhir.context.RuntimeChildDirectResource;
-import ca.uhn.fhir.context.RuntimeExtensionDtDefinition;
-import ca.uhn.fhir.context.RuntimeResourceDefinition;
-import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ISupportsUndeclaredExtensions;
@@ -20,30 +10,14 @@ import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.Validate;
-import org.hl7.fhir.instance.model.api.IBase;
-import org.hl7.fhir.instance.model.api.IBaseExtension;
-import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
-import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
-import org.hl7.fhir.instance.model.api.IBaseReference;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.instance.model.api.*;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Optional;
+import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
-import static org.apache.commons.lang3.StringUtils.defaultString;
-import static org.apache.commons.lang3.StringUtils.isBlank;
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
+import static org.apache.commons.lang3.StringUtils.*;
/*
* #%L
@@ -267,11 +241,6 @@ public class FhirTerser {
return retVal.get(0);
}
- public Optional getSingleValue(IBase theTarget, String thePath, Class theWantedType) {
- return Optional.ofNullable(getSingleValueOrNull(theTarget, thePath, theWantedType));
- }
-
-
private List getValues(BaseRuntimeElementCompositeDefinition> theCurrentDef, IBase theCurrentObj, List theSubList, Class theWantedClass) {
return getValues(theCurrentDef, theCurrentObj, theSubList, theWantedClass, false, false);
}
@@ -502,85 +471,85 @@ public class FhirTerser {
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
- * @param theElement The element to be accessed. Must not be null.
- * @param thePath The path for the element to be accessed.@param theElement The resource instance to be accessed. Must not be null.
+ * @param theResource The resource instance to be accessed. Must not be null.
+ * @param thePath The path for the element to be accessed.
* @return A list of values of type {@link Object}.
*/
- public List getValues(IBase theElement, String thePath) {
+ public List getValues(IBaseResource theResource, String thePath) {
Class wantedClass = IBase.class;
- return getValues(theElement, thePath, wantedClass);
+ return getValues(theResource, thePath, wantedClass);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
- * @param theElement The element to be accessed. Must not be null.
- * @param thePath The path for the element to be accessed.
- * @param theCreate When set to true
, the terser will create a null-valued element where none exists.
+ * @param theResource The resource instance to be accessed. Must not be null.
+ * @param thePath The path for the element to be accessed.
+ * @param theCreate When set to true
, the terser will create a null-valued element where none exists.
* @return A list of values of type {@link Object}.
*/
- public List getValues(IBase theElement, String thePath, boolean theCreate) {
+ public List getValues(IBaseResource theResource, String thePath, boolean theCreate) {
Class wantedClass = IBase.class;
- return getValues(theElement, thePath, wantedClass, theCreate);
+ return getValues(theResource, thePath, wantedClass, theCreate);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type {@link Object}.
*
- * @param theElement The element to be accessed. Must not be null.
+ * @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theCreate When set to true
, the terser will create a null-valued element where none exists.
* @param theAddExtension When set to true
, the terser will add a null-valued extension where one or more such extensions already exist.
* @return A list of values of type {@link Object}.
*/
- public List getValues(IBase theElement, String thePath, boolean theCreate, boolean theAddExtension) {
+ public List getValues(IBaseResource theResource, String thePath, boolean theCreate, boolean theAddExtension) {
Class wantedClass = IBase.class;
- return getValues(theElement, thePath, wantedClass, theCreate, theAddExtension);
+ return getValues(theResource, thePath, wantedClass, theCreate, theAddExtension);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type theWantedClass
.
*
- * @param theElement The element to be accessed. Must not be null.
+ * @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param Type declared by theWantedClass
* @return A list of values of type theWantedClass
.
*/
- public List getValues(IBase theElement, String thePath, Class theWantedClass) {
- BaseRuntimeElementCompositeDefinition> def = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition(theElement.getClass());
+ public List getValues(IBaseResource theResource, String thePath, Class theWantedClass) {
+ RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List parts = parsePath(def, thePath);
- return getValues(def, theElement, parts, theWantedClass);
+ return getValues(def, theResource, parts, theWantedClass);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type theWantedClass
.
*
- * @param theElement The element to be accessed. Must not be null.
+ * @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param theCreate When set to true
, the terser will create a null-valued element where none exists.
* @param Type declared by theWantedClass
* @return A list of values of type theWantedClass
.
*/
- public List getValues(IBase theElement, String thePath, Class theWantedClass, boolean theCreate) {
- BaseRuntimeElementCompositeDefinition> def = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition(theElement.getClass());
+ public List getValues(IBaseResource theResource, String thePath, Class theWantedClass, boolean theCreate) {
+ RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List parts = parsePath(def, thePath);
- return getValues(def, theElement, parts, theWantedClass, theCreate, false);
+ return getValues(def, theResource, parts, theWantedClass, theCreate, false);
}
/**
* Returns values stored in an element identified by its path. The list of values is of
* type theWantedClass
.
*
- * @param theElement The element to be accessed. Must not be null.
+ * @param theResource The resource instance to be accessed. Must not be null.
* @param thePath The path for the element to be accessed.
* @param theWantedClass The desired class to be returned in a list.
* @param theCreate When set to true
, the terser will create a null-valued element where none exists.
@@ -588,10 +557,10 @@ public class FhirTerser {
* @param Type declared by theWantedClass
* @return A list of values of type theWantedClass
.
*/
- public List getValues(IBase theElement, String thePath, Class theWantedClass, boolean theCreate, boolean theAddExtension) {
- BaseRuntimeElementCompositeDefinition> def = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition(theElement.getClass());
+ public List getValues(IBaseResource theResource, String thePath, Class theWantedClass, boolean theCreate, boolean theAddExtension) {
+ RuntimeResourceDefinition def = myContext.getResourceDefinition(theResource);
List parts = parsePath(def, thePath);
- return getValues(def, theElement, parts, theWantedClass, theCreate, theAddExtension);
+ return getValues(def, theResource, parts, theWantedClass, theCreate, theAddExtension);
}
private List parsePath(BaseRuntimeElementCompositeDefinition> theElementDef, String thePath) {
@@ -832,7 +801,7 @@ public class FhirTerser {
}
/**
- * Visit all elements in a given resource or element
+ * Visit all elements in a given resource
*
* THIS ALTERNATE METHOD IS STILL EXPERIMENTAL! USE WITH CAUTION
*
@@ -841,19 +810,12 @@ public class FhirTerser {
* {@link BaseResourceReferenceDt#getResource()}) or embedded resources (e.g. Bundle.entry.resource)
*
*
- * @param theElement The element to visit
- * @param theVisitor The visitor
+ * @param theResource The resource to visit
+ * @param theVisitor The visitor
*/
- public void visit(IBase theElement, IModelVisitor2 theVisitor) {
- BaseRuntimeElementDefinition> def = myContext.getElementDefinition(theElement.getClass());
- if (def instanceof BaseRuntimeElementCompositeDefinition) {
- BaseRuntimeElementCompositeDefinition> defComposite = (BaseRuntimeElementCompositeDefinition>) def;
- visit(theElement, null, def, theVisitor, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
- } else if (theElement instanceof IBaseExtension) {
- theVisitor.acceptUndeclaredExtension((IBaseExtension, ?>) theElement, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
- } else {
- theVisitor.acceptElement(theElement, Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
- }
+ public void visit(IBaseResource theResource, IModelVisitor2 theVisitor) {
+ BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theResource);
+ visit(theResource, null, def, theVisitor, new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
}
private void visit(Map theStack, IBaseResource theResource, IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition,
@@ -1009,5 +971,4 @@ public class FhirTerser {
});
}
-
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java
index ace55587c7b..a28197931be 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java
@@ -20,26 +20,17 @@ package ca.uhn.fhir.util;
* #L%
*/
-import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
-import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
-import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.context.RuntimeResourceDefinition;
+import ca.uhn.fhir.context.*;
import ca.uhn.fhir.model.primitive.StringDt;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
-import org.hl7.fhir.instance.model.api.IBase;
-import org.hl7.fhir.instance.model.api.IBaseDatatype;
-import org.hl7.fhir.instance.model.api.IBaseParameters;
-import org.hl7.fhir.instance.model.api.IBaseReference;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.instance.model.api.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
-import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
@@ -54,7 +45,7 @@ public class ParametersUtil {
}
public static List getNamedParameterValuesAsInteger(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
- Function, Integer> mapper = t -> (Integer) t.getValue();
+ Function, Integer> mapper = t -> (Integer)t.getValue();
return extractNamedParameters(theCtx, theParameters, theParameterName, mapper);
}
@@ -62,72 +53,33 @@ public class ParametersUtil {
return getNamedParameterValuesAsInteger(theCtx, theParameters, theParameterName).stream().findFirst();
}
- public static List getNamedParameters(FhirContext theCtx, IBaseResource theParameters, String theParameterName) {
+ private static List extractNamedParameters(FhirContext theCtx, IBaseParameters theParameters, String theParameterName, Function, T> theMapper) {
Validate.notNull(theParameters, "theParameters must not be null");
RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass());
BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter");
List parameterReps = parameterChild.getAccessor().getValues(theParameters);
- return parameterReps
- .stream()
- .filter(param -> {
- BaseRuntimeElementCompositeDefinition> nextParameterDef = (BaseRuntimeElementCompositeDefinition>) theCtx.getElementDefinition(param.getClass());
- BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name");
- List nameValues = nameChild.getAccessor().getValues(param);
- Optional extends IPrimitiveType>> nameValue = nameValues
- .stream()
- .filter(t -> t instanceof IPrimitiveType>)
- .map(t -> ((IPrimitiveType>) t))
- .findFirst();
- if (!nameValue.isPresent() || !theParameterName.equals(nameValue.get().getValueAsString())) {
- return false;
- }
- return true;
- })
- .collect(Collectors.toList());
-
- }
-
- public static Optional getParameterPart(FhirContext theCtx, IBase theParameter, String theParameterName) {
- BaseRuntimeElementCompositeDefinition> nextParameterDef = (BaseRuntimeElementCompositeDefinition>) theCtx.getElementDefinition(theParameter.getClass());
- BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("part");
- List parts = valueChild.getAccessor().getValues(theParameter);
-
- for (IBase nextPart : parts) {
- Optional name = theCtx.newTerser().getSingleValue(nextPart, "name", IPrimitiveType.class);
- if (name.isPresent() && theParameterName.equals(name.get().getValueAsString())) {
- return Optional.of(nextPart);
- }
- }
-
- return Optional.empty();
- }
-
- public static Optional getParameterPartValue(FhirContext theCtx, IBase theParameter, String theParameterName) {
- Optional part = getParameterPart(theCtx, theParameter, theParameterName);
- if (part.isPresent()) {
- return theCtx.newTerser().getSingleValue(part.get(), "value[x]", IBase.class);
- } else {
- return Optional.empty();
- }
- }
-
- public static String getParameterPartValueAsString(FhirContext theCtx, IBase theParameter, String theParameterName) {
- return getParameterPartValue(theCtx, theParameter, theParameterName).map(t -> (IPrimitiveType>) t).map(t -> t.getValueAsString()).orElse(null);
- }
-
- private static List extractNamedParameters(FhirContext theCtx, IBaseParameters theParameters, String theParameterName, Function, T> theMapper) {
List retVal = new ArrayList<>();
- List namedParameters = getNamedParameters(theCtx, theParameters, theParameterName);
- for (IBase nextParameter : namedParameters) {
+ for (IBase nextParameter : parameterReps) {
BaseRuntimeElementCompositeDefinition> nextParameterDef = (BaseRuntimeElementCompositeDefinition>) theCtx.getElementDefinition(nextParameter.getClass());
+ BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name");
+ List nameValues = nameChild.getAccessor().getValues(nextParameter);
+ Optional extends IPrimitiveType>> nameValue = nameValues
+ .stream()
+ .filter(t -> t instanceof IPrimitiveType>)
+ .map(t -> ((IPrimitiveType>) t))
+ .findFirst();
+ if (!nameValue.isPresent() || !theParameterName.equals(nameValue.get().getValueAsString())) {
+ continue;
+ }
+
BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("value[x]");
List valueValues = valueChild.getAccessor().getValues(nextParameter);
valueValues
.stream()
.filter(t -> t instanceof IPrimitiveType>)
- .map(t -> ((IPrimitiveType>) t))
+ .map(t->((IPrimitiveType>) t))
.map(theMapper)
.filter(t -> t != null)
.forEach(retVal::add);
@@ -285,13 +237,6 @@ public class ParametersUtil {
addPart(theContext, theParameter, theName, value);
}
- public static void addPartInteger(FhirContext theContext, IBase theParameter, String theName, Integer theInteger) {
- IPrimitiveType value = (IPrimitiveType) theContext.getElementDefinition("integer").newInstance();
- value.setValue(theInteger);
-
- addPart(theContext, theParameter, theName, value);
- }
-
public static void addPartString(FhirContext theContext, IBase theParameter, String theName, String theValue) {
IPrimitiveType value = (IPrimitiveType) theContext.getElementDefinition("string").newInstance();
value.setValue(theValue);
@@ -339,5 +284,4 @@ public class ParametersUtil {
partChildElem.getChildByName("resource").getMutator().addValue(part, theValue);
}
-
}
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java
index 0ce84915101..b2edb9a22cf 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/XmlUtil.java
@@ -31,42 +31,16 @@ import org.apache.commons.text.StringEscapeUtils;
import org.codehaus.stax2.XMLOutputFactory2;
import org.codehaus.stax2.io.EscapingWriterFactory;
import org.w3c.dom.Document;
-import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.stream.FactoryConfigurationError;
-import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLOutputFactory;
-import javax.xml.stream.XMLResolver;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
+import javax.xml.stream.*;
import javax.xml.stream.events.XMLEvent;
-import javax.xml.transform.OutputKeys;
-import javax.xml.transform.Transformer;
-import javax.xml.transform.TransformerConfigurationException;
-import javax.xml.transform.TransformerException;
-import javax.xml.transform.TransformerFactory;
-import javax.xml.transform.dom.DOMSource;
-import javax.xml.transform.stream.StreamResult;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.UnsupportedEncodingException;
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.*;
+import java.util.*;
import static org.apache.commons.lang3.StringUtils.isBlank;
@@ -1539,11 +1513,8 @@ public class XmlUtil {
VALID_ENTITY_NAMES = Collections.unmodifiableMap(validEntityNames);
}
- /**
- * Non-instantiable
- */
- private XmlUtil() {
- }
+ /** Non-instantiable */
+ private XmlUtil() {}
private static final class ExtendedEntityReplacingXmlResolver implements XMLResolver {
@Override
@@ -1864,7 +1835,7 @@ public class XmlUtil {
}
public static Document parseDocument(String theInput) throws IOException, SAXException {
- DocumentBuilder builder;
+ DocumentBuilder builder = null;
try {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilderFactory.setNamespaceAware(true);
@@ -1889,13 +1860,4 @@ public class XmlUtil {
InputSource src = new InputSource(new StringReader(theInput));
return builder.parse(src);
}
-
- public static String encodeDocument(Element theElement) throws TransformerException {
- TransformerFactory transFactory = TransformerFactory.newInstance();
- Transformer transformer = transFactory.newTransformer();
- StringWriter buffer = new StringWriter();
- transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
- transformer.transform(new DOMSource(theElement), new StreamResult(buffer));
- return buffer.toString();
- }
}
diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
index 6ae6f2faf34..ac017230a12 100644
--- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
+++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties
@@ -106,10 +106,6 @@ ca.uhn.fhir.jpa.dao.TransactionProcessor.missingMandatoryResource=Missing requir
ca.uhn.fhir.jpa.dao.TransactionProcessor.missingPatchContentType=Missing or invalid content type for PATCH operation
ca.uhn.fhir.jpa.dao.TransactionProcessor.missingPatchBody=Unable to determine PATCH body from request
-ca.uhn.fhir.jpa.patch.FhirPatch.invalidInsertIndex=Invalid insert index {0} for path {1} - Only have {2} existing entries
-ca.uhn.fhir.jpa.patch.FhirPatch.invalidMoveSourceIndex=Invalid move source index {0} for path {1} - Only have {2} existing entries
-ca.uhn.fhir.jpa.patch.FhirPatch.invalidMoveDestinationIndex=Invalid move destination index {0} for path {1} - Only have {2} existing entries
-
ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.externalReferenceNotAllowed=Resource contains external reference to URL "{0}" but this server is not configured to allow external references
ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor.failedToExtractPaths=Failed to extract values from resource using FHIRPath "{0}": {1}
@@ -143,7 +139,7 @@ ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateConceptMapUrl=Can
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.cannotCreateDuplicateValueSetUrl=Can not create multiple ValueSet resources with ValueSet.url "{0}", already have one with resource ID: {1}
ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.expansionTooLarge=Expansion of ValueSet produced too many codes (maximum {0}) - Operation aborted!
-ca.uhn.fhir.jpa.patch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
+ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils.failedToApplyPatch=Failed to apply JSON patch to {0}: {1}
ca.uhn.fhir.jpa.graphql.JpaStorageServices.invalidGraphqlArgument=Unknown GraphQL argument "{0}". Value GraphQL argument for this type are: {1}
diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java
index a54e208322f..63e92b431a0 100644
--- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java
+++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java
@@ -1617,16 +1617,6 @@ public class GenericClient extends BaseClient implements IGenericClient {
return this;
}
- @Override
- public IPatchWithBody withFhirPatch(IBaseParameters thePatchBody) {
- Validate.notNull(thePatchBody, "thePatchBody must not be null");
-
- myPatchType = PatchTypeEnum.FHIR_PATCH_JSON;
- myPatchBody = myContext.newJsonParser().encodeResourceToString(thePatchBody);
-
- return this;
- }
-
@Override
public IPatchExecutable withId(IIdType theId) {
if (theId == null) {
diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java
index abf4aa75b2c..c9079b7898a 100644
--- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java
+++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java
@@ -32,321 +32,243 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
+import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
-import org.hl7.fhir.r4.model.Bundle;
-import org.hl7.fhir.r4.model.CapabilityStatement;
-import org.hl7.fhir.r4.model.CodeType;
-import org.hl7.fhir.r4.model.DateType;
-import org.hl7.fhir.r4.model.Enumerations;
-import org.hl7.fhir.r4.model.IdType;
-import org.hl7.fhir.r4.model.InstantType;
-import org.hl7.fhir.r4.model.Observation;
-import org.hl7.fhir.r4.model.OperationOutcome;
-import org.hl7.fhir.r4.model.Organization;
-import org.hl7.fhir.r4.model.Parameters;
-import org.hl7.fhir.r4.model.Patient;
-import org.hl7.fhir.r4.model.Provenance;
-import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.*;
import java.util.ArrayList;
import java.util.List;
public class GenericClientExample {
- public static void deferModelScanning() {
- // START SNIPPET: deferModelScanning
- // Create a context and configure it for deferred child scanning
- FhirContext ctx = FhirContext.forDstu2();
- ctx.setPerformanceOptions(PerformanceOptionsEnum.DEFERRED_MODEL_SCANNING);
+ public static void deferModelScanning() {
+ // START SNIPPET: deferModelScanning
+ // Create a context and configure it for deferred child scanning
+ FhirContext ctx = FhirContext.forDstu2();
+ ctx.setPerformanceOptions(PerformanceOptionsEnum.DEFERRED_MODEL_SCANNING);
+
+ // Now create a client and use it
+ String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
+ IGenericClient client = ctx.newRestfulGenericClient(serverBase);
+ // END SNIPPET: deferModelScanning
+ }
+
+ public static void performance() {
+ // START SNIPPET: dontValidate
+ // Create a context
+ FhirContext ctx = FhirContext.forDstu2();
- // Now create a client and use it
- String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
- IGenericClient client = ctx.newRestfulGenericClient(serverBase);
- // END SNIPPET: deferModelScanning
- }
+ // Disable server validation (don't pull the server's metadata first)
+ ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
+
+ // Now create a client and use it
+ String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
+ IGenericClient client = ctx.newRestfulGenericClient(serverBase);
+ // END SNIPPET: dontValidate
+ }
+
+ public static void simpleExample() {
+ // START SNIPPET: simple
+ // We're connecting to a DSTU1 compliant server in this example
+ FhirContext ctx = FhirContext.forDstu2();
+ String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
+
+ IGenericClient client = ctx.newRestfulGenericClient(serverBase);
- public static void performance() {
- // START SNIPPET: dontValidate
- // Create a context
- FhirContext ctx = FhirContext.forDstu2();
+ // Perform a search
+ Bundle results = client
+ .search()
+ .forResource(Patient.class)
+ .where(Patient.FAMILY.matches().value("duck"))
+ .returnBundle(Bundle.class)
+ .execute();
- // Disable server validation (don't pull the server's metadata first)
- ctx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
+ System.out.println("Found " + results.getEntry().size() + " patients named 'duck'");
+ // END SNIPPET: simple
+ }
- // Now create a client and use it
- String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
- IGenericClient client = ctx.newRestfulGenericClient(serverBase);
- // END SNIPPET: dontValidate
- }
+ @SuppressWarnings("unused")
+ public static void fluentSearch() {
+ FhirContext ctx = FhirContext.forDstu2();
+ IGenericClient client = ctx.newRestfulGenericClient("http://fhir.healthintersections.com.au/open");
+ {
+ // START SNIPPET: create
+ Patient patient = new Patient();
+ // ..populate the patient object..
+ patient.addIdentifier().setSystem("urn:system").setValue("12345");
+ patient.addName().setFamily("Smith").addGiven("John");
- public static void patchFhir() {
- // Create a context
- FhirContext ctx = FhirContext.forR4();
+ // Invoke the server create method (and send pretty-printed JSON
+ // encoding to the server
+ // instead of the default which is non-pretty printed XML)
+ MethodOutcome outcome = client.create()
+ .resource(patient)
+ .prettyPrint()
+ .encodedJson()
+ .execute();
+
+ // The MethodOutcome object will contain information about the
+ // response from the server, including the ID of the created
+ // resource, the OperationOutcome response, etc. (assuming that
+ // any of these things were provided by the server! They may not
+ // always be)
+ IIdType id = outcome.getId();
+ System.out.println("Got ID: " + id.getValue());
+ // END SNIPPET: create
+ }
+ {
+ Patient patient = new Patient();
+ // START SNIPPET: createConditional
+ // One form
+ MethodOutcome outcome = client.create()
+ .resource(patient)
+ .conditionalByUrl("Patient?identifier=system%7C00001")
+ .execute();
- // START SNIPPET: patchFhir
- // Create a client
- String serverBase = "http://hapi.fhir.org/baseR4";
- IGenericClient client = ctx.newRestfulGenericClient(serverBase);
+ // Another form
+ MethodOutcome outcome2 = client.create()
+ .resource(patient)
+ .conditional()
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
+ .execute();
- // Create a patch object
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("delete"));
- operation
- .addPart()
- .setName("path")
- .setValue(new StringType("Patient.identifier[0]"));
+ // This will return Boolean.TRUE if the server responded with an HTTP 201 created,
+ // otherwise it will return null.
+ Boolean created = outcome.getCreated();
- // Invoke the patch
- MethodOutcome outcome = client
- .patch()
- .withFhirPatch(patch)
- .withId("Patient/123")
- .execute();
+ // The ID of the created, or the pre-existing resource
+ IIdType id = outcome.getId();
+ // END SNIPPET: createConditional
+ }
+ {
+ // START SNIPPET: validate
+ Patient patient = new Patient();
+ patient.addIdentifier().setSystem("http://hospital.com").setValue("123445");
+ patient.addName().setFamily("Smith").addGiven("John");
+
+ // Validate the resource
+ MethodOutcome outcome = client.validate()
+ .resource(patient)
+ .execute();
+
+ // The returned object will contain an operation outcome resource
+ OperationOutcome oo = (OperationOutcome) outcome.getOperationOutcome();
+
+ // If the OperationOutcome has any issues with a severity of ERROR or SEVERE,
+ // the validation failed.
+ for (OperationOutcome.OperationOutcomeIssueComponent nextIssue : oo.getIssue()) {
+ if (nextIssue.getSeverity().ordinal() >= OperationOutcome.IssueSeverity.ERROR.ordinal()) {
+ System.out.println("We failed validation!");
+ }
+ }
+ // END SNIPPET: validate
+ }
+ {
+ // START SNIPPET: update
+ Patient patient = new Patient();
+ // ..populate the patient object..
+ patient.addIdentifier().setSystem("urn:system").setValue("12345");
+ patient.addName().setFamily("Smith").addGiven("John");
- // The server may provide the updated contents in the response
- Patient resultingResource = (Patient) outcome.getResource();
+ // To update a resource, it should have an ID set (if the resource
+ // object
+ // comes from the results of a previous read or search, it will already
+ // have one though)
+ patient.setId("Patient/123");
- // END SNIPPET: patchFhir
- }
+ // Invoke the server update method
+ MethodOutcome outcome = client.update()
+ .resource(patient)
+ .execute();
- public static void patchJson() {
- // Create a context
- FhirContext ctx = FhirContext.forR4();
+ // The MethodOutcome object will contain information about the
+ // response from the server, including the ID of the created
+ // resource, the OperationOutcome response, etc. (assuming that
+ // any of these things were provided by the server! They may not
+ // always be)
+ IdType id = (IdType) outcome.getId();
+ System.out.println("Got ID: " + id.getValue());
+ // END SNIPPET: update
+ }
+ {
+ Patient patient = new Patient();
+ // START SNIPPET: updateConditional
+ client.update()
+ .resource(patient)
+ .conditionalByUrl("Patient?identifier=system%7C00001")
+ .execute();
- // START SNIPPET: patchJson
- // Create a client
- String serverBase = "http://hapi.fhir.org/baseR4";
- IGenericClient client = ctx.newRestfulGenericClient(serverBase);
+ client.update()
+ .resource(patient)
+ .conditional()
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
+ .execute();
+ // END SNIPPET: updateConditional
+ }
+ {
+ // START SNIPPET: etagupdate
+ // First, let's retrieve the latest version of a resource
+ // from the server
+ Patient patient = client.read().resource(Patient.class).withId("123").execute();
- // Create a JSON patch object
- String patch = "[ " +
- " { " +
- " \"op\":\"replace\", " +
- " \"path\":\"/active\", " +
- " \"value\":false " +
- " } " +
- "]";
+ // If the server is a version aware server, we should now know the latest version
+ // of the resource
+ System.out.println("Version ID: " + patient.getIdElement().getVersionIdPart());
+
+ // Now let's make a change to the resource
+ patient.setGender(Enumerations.AdministrativeGender.FEMALE);
- // Invoke the patch
- MethodOutcome outcome = client
- .patch()
- .withBody(patch)
- .withId("Patient/123")
- .execute();
-
- // The server may provide the updated contents in the response
- Patient resultingResource = (Patient) outcome.getResource();
-
- // END SNIPPET: patchJson
- }
-
- public static void simpleExample() {
- // START SNIPPET: simple
- // We're connecting to a DSTU1 compliant server in this example
- FhirContext ctx = FhirContext.forDstu2();
- String serverBase = "http://fhirtest.uhn.ca/baseDstu2";
-
- IGenericClient client = ctx.newRestfulGenericClient(serverBase);
-
- // Perform a search
- Bundle results = client
- .search()
- .forResource(Patient.class)
- .where(Patient.FAMILY.matches().value("duck"))
- .returnBundle(Bundle.class)
- .execute();
-
- System.out.println("Found " + results.getEntry().size() + " patients named 'duck'");
- // END SNIPPET: simple
- }
-
- @SuppressWarnings("unused")
- public static void fluentSearch() {
- FhirContext ctx = FhirContext.forDstu2();
- IGenericClient client = ctx.newRestfulGenericClient("http://fhir.healthintersections.com.au/open");
- {
- // START SNIPPET: create
- Patient patient = new Patient();
- // ..populate the patient object..
- patient.addIdentifier().setSystem("urn:system").setValue("12345");
- patient.addName().setFamily("Smith").addGiven("John");
-
- // Invoke the server create method (and send pretty-printed JSON
- // encoding to the server
- // instead of the default which is non-pretty printed XML)
- MethodOutcome outcome = client.create()
- .resource(patient)
- .prettyPrint()
- .encodedJson()
- .execute();
-
- // The MethodOutcome object will contain information about the
- // response from the server, including the ID of the created
- // resource, the OperationOutcome response, etc. (assuming that
- // any of these things were provided by the server! They may not
- // always be)
- IIdType id = outcome.getId();
- System.out.println("Got ID: " + id.getValue());
- // END SNIPPET: create
- }
- {
- Patient patient = new Patient();
- // START SNIPPET: createConditional
- // One form
- MethodOutcome outcome = client.create()
- .resource(patient)
- .conditionalByUrl("Patient?identifier=system%7C00001")
- .execute();
-
- // Another form
- MethodOutcome outcome2 = client.create()
- .resource(patient)
- .conditional()
- .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
- .execute();
-
- // This will return Boolean.TRUE if the server responded with an HTTP 201 created,
- // otherwise it will return null.
- Boolean created = outcome.getCreated();
-
- // The ID of the created, or the pre-existing resource
- IIdType id = outcome.getId();
- // END SNIPPET: createConditional
- }
- {
- // START SNIPPET: validate
- Patient patient = new Patient();
- patient.addIdentifier().setSystem("http://hospital.com").setValue("123445");
- patient.addName().setFamily("Smith").addGiven("John");
-
- // Validate the resource
- MethodOutcome outcome = client.validate()
- .resource(patient)
- .execute();
-
- // The returned object will contain an operation outcome resource
- OperationOutcome oo = (OperationOutcome) outcome.getOperationOutcome();
-
- // If the OperationOutcome has any issues with a severity of ERROR or SEVERE,
- // the validation failed.
- for (OperationOutcome.OperationOutcomeIssueComponent nextIssue : oo.getIssue()) {
- if (nextIssue.getSeverity().ordinal() >= OperationOutcome.IssueSeverity.ERROR.ordinal()) {
- System.out.println("We failed validation!");
- }
- }
- // END SNIPPET: validate
- }
- {
- // START SNIPPET: update
- Patient patient = new Patient();
- // ..populate the patient object..
- patient.addIdentifier().setSystem("urn:system").setValue("12345");
- patient.addName().setFamily("Smith").addGiven("John");
-
- // To update a resource, it should have an ID set (if the resource
- // object
- // comes from the results of a previous read or search, it will already
- // have one though)
- patient.setId("Patient/123");
-
- // Invoke the server update method
- MethodOutcome outcome = client.update()
- .resource(patient)
- .execute();
-
- // The MethodOutcome object will contain information about the
- // response from the server, including the ID of the created
- // resource, the OperationOutcome response, etc. (assuming that
- // any of these things were provided by the server! They may not
- // always be)
- IdType id = (IdType) outcome.getId();
- System.out.println("Got ID: " + id.getValue());
- // END SNIPPET: update
- }
- {
- Patient patient = new Patient();
- // START SNIPPET: updateConditional
- client.update()
- .resource(patient)
- .conditionalByUrl("Patient?identifier=system%7C00001")
- .execute();
-
- client.update()
- .resource(patient)
- .conditional()
- .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
- .execute();
- // END SNIPPET: updateConditional
- }
- {
- // START SNIPPET: etagupdate
- // First, let's retrieve the latest version of a resource
- // from the server
- Patient patient = client.read().resource(Patient.class).withId("123").execute();
-
- // If the server is a version aware server, we should now know the latest version
- // of the resource
- System.out.println("Version ID: " + patient.getIdElement().getVersionIdPart());
-
- // Now let's make a change to the resource
- patient.setGender(Enumerations.AdministrativeGender.FEMALE);
-
- // Invoke the server update method - Because the resource has
- // a version, it will be included in the request sent to
- // the server
- try {
- MethodOutcome outcome = client
- .update()
- .resource(patient)
- .execute();
- } catch (PreconditionFailedException e) {
- // If we get here, the latest version has changed
- // on the server so our update failed.
- }
- // END SNIPPET: etagupdate
- }
- {
- // START SNIPPET: conformance
- // Retrieve the server's conformance statement and print its
- // description
- CapabilityStatement conf = client
+ // Invoke the server update method - Because the resource has
+ // a version, it will be included in the request sent to
+ // the server
+ try {
+ MethodOutcome outcome = client
+ .update()
+ .resource(patient)
+ .execute();
+ } catch (PreconditionFailedException e) {
+ // If we get here, the latest version has changed
+ // on the server so our update failed.
+ }
+ // END SNIPPET: etagupdate
+ }
+ {
+ // START SNIPPET: conformance
+ // Retrieve the server's conformance statement and print its
+ // description
+ CapabilityStatement conf = client
.capabilities()
.ofType(CapabilityStatement.class)
.execute();
- System.out.println(conf.getDescriptionElement().getValue());
- // END SNIPPET: conformance
- }
- {
- // START SNIPPET: delete
+ System.out.println(conf.getDescriptionElement().getValue());
+ // END SNIPPET: conformance
+ }
+ {
+ // START SNIPPET: delete
MethodOutcome response = client
.delete()
.resourceById(new IdType("Patient", "1234"))
.execute();
- // outcome may be null if the server didn't return one
+ // outcome may be null if the server didn't return one
OperationOutcome outcome = (OperationOutcome) response.getOperationOutcome();
if (outcome != null) {
System.out.println(outcome.getIssueFirstRep().getDetails().getCodingFirstRep().getCode());
}
// END SNIPPET: delete
}
- {
- // START SNIPPET: deleteConditional
- client.delete()
- .resourceConditionalByUrl("Patient?identifier=system%7C00001")
- .execute();
+ {
+ // START SNIPPET: deleteConditional
+ client.delete()
+ .resourceConditionalByUrl("Patient?identifier=system%7C00001")
+ .execute();
- client.delete()
- .resourceConditionalByType("Patient")
- .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
- .execute();
- // END SNIPPET: deleteConditional
- }
+ client.delete()
+ .resourceConditionalByType("Patient")
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("system", "00001"))
+ .execute();
+ // END SNIPPET: deleteConditional
+ }
{
// START SNIPPET: deleteCascade
client.delete()
@@ -360,292 +282,292 @@ public class GenericClientExample {
.execute();
// END SNIPPET: deleteCascade
}
- {
- // START SNIPPET: search
- Bundle response = client.search()
- .forResource(Patient.class)
- .where(Patient.BIRTHDATE.beforeOrEquals().day("2011-01-01"))
- .and(Patient.GENERAL_PRACTITIONER.hasChainedProperty(Organization.NAME.matches().value("Smith")))
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: search
+ {
+ // START SNIPPET: search
+ Bundle response = client.search()
+ .forResource(Patient.class)
+ .where(Patient.BIRTHDATE.beforeOrEquals().day("2011-01-01"))
+ .and(Patient.GENERAL_PRACTITIONER.hasChainedProperty(Organization.NAME.matches().value("Smith")))
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: search
- // START SNIPPET: searchOr
- response = client.search()
- .forResource(Patient.class)
- .where(Patient.FAMILY.matches().values("Smith", "Smyth"))
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchOr
+ // START SNIPPET: searchOr
+ response = client.search()
+ .forResource(Patient.class)
+ .where(Patient.FAMILY.matches().values("Smith", "Smyth"))
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchOr
- // START SNIPPET: searchAnd
- response = client.search()
- .forResource(Patient.class)
- .where(Patient.ADDRESS.matches().values("Toronto"))
- .and(Patient.ADDRESS.matches().values("Ontario"))
- .and(Patient.ADDRESS.matches().values("Canada"))
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchAnd
+ // START SNIPPET: searchAnd
+ response = client.search()
+ .forResource(Patient.class)
+ .where(Patient.ADDRESS.matches().values("Toronto"))
+ .and(Patient.ADDRESS.matches().values("Ontario"))
+ .and(Patient.ADDRESS.matches().values("Canada"))
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchAnd
- // START SNIPPET: searchCompartment
- response = client.search()
- .forResource(Patient.class)
- .withIdAndCompartment("123", "condition")
- .where(Patient.ADDRESS.matches().values("Toronto"))
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchCompartment
+ // START SNIPPET: searchCompartment
+ response = client.search()
+ .forResource(Patient.class)
+ .withIdAndCompartment("123", "condition")
+ .where(Patient.ADDRESS.matches().values("Toronto"))
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchCompartment
- // START SNIPPET: searchUrl
- String searchUrl = "http://example.com/base/Patient?identifier=foo";
+ // START SNIPPET: searchUrl
+ String searchUrl = "http://example.com/base/Patient?identifier=foo";
+
+ // Search URL can also be a relative URL in which case the client's base
+ // URL will be added to it
+ searchUrl = "Patient?identifier=foo";
+
+ response = client.search()
+ .byUrl(searchUrl)
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchUrl
- // Search URL can also be a relative URL in which case the client's base
- // URL will be added to it
- searchUrl = "Patient?identifier=foo";
+ // START SNIPPET: searchSubsetSummary
+ response = client.search()
+ .forResource(Patient.class)
+ .where(Patient.ADDRESS.matches().values("Toronto"))
+ .returnBundle(Bundle.class)
+ .summaryMode(SummaryEnum.TRUE)
+ .execute();
+ // END SNIPPET: searchSubsetSummary
- response = client.search()
- .byUrl(searchUrl)
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchUrl
+ // START SNIPPET: searchSubsetElements
+ response = client.search()
+ .forResource(Patient.class)
+ .where(Patient.ADDRESS.matches().values("Toronto"))
+ .returnBundle(Bundle.class)
+ .elementsSubset("identifier", "name") // only include the identifier and name
+ .execute();
+ // END SNIPPET: searchSubsetElements
- // START SNIPPET: searchSubsetSummary
- response = client.search()
- .forResource(Patient.class)
- .where(Patient.ADDRESS.matches().values("Toronto"))
- .returnBundle(Bundle.class)
- .summaryMode(SummaryEnum.TRUE)
- .execute();
- // END SNIPPET: searchSubsetSummary
+ // START SNIPPET: searchAdv
+ response = client.search()
+ .forResource(Patient.class)
+ .encodedJson()
+ .where(Patient.BIRTHDATE.beforeOrEquals().day("2012-01-22"))
+ .and(Patient.BIRTHDATE.after().day("2011-01-01"))
+ .withTag("http://acme.org/codes", "needs-review")
+ .include(Patient.INCLUDE_ORGANIZATION.asRecursive())
+ .include(Patient.INCLUDE_GENERAL_PRACTITIONER.asNonRecursive())
+ .revInclude(Provenance.INCLUDE_TARGET)
+ .lastUpdated(new DateRangeParam("2011-01-01", null))
+ .sort().ascending(Patient.BIRTHDATE)
+ .sort().descending(Patient.NAME)
+ .count(123)
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchAdv
- // START SNIPPET: searchSubsetElements
- response = client.search()
- .forResource(Patient.class)
- .where(Patient.ADDRESS.matches().values("Toronto"))
- .returnBundle(Bundle.class)
- .elementsSubset("identifier", "name") // only include the identifier and name
- .execute();
- // END SNIPPET: searchSubsetElements
+ // START SNIPPET: searchPost
+ response = client.search()
+ .forResource("Patient")
+ .where(Patient.NAME.matches().value("Tester"))
+ .usingStyle(SearchStyleEnum.POST)
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchPost
- // START SNIPPET: searchAdv
- response = client.search()
- .forResource(Patient.class)
- .encodedJson()
- .where(Patient.BIRTHDATE.beforeOrEquals().day("2012-01-22"))
- .and(Patient.BIRTHDATE.after().day("2011-01-01"))
- .withTag("http://acme.org/codes", "needs-review")
- .include(Patient.INCLUDE_ORGANIZATION.asRecursive())
- .include(Patient.INCLUDE_GENERAL_PRACTITIONER.asNonRecursive())
- .revInclude(Provenance.INCLUDE_TARGET)
- .lastUpdated(new DateRangeParam("2011-01-01", null))
- .sort().ascending(Patient.BIRTHDATE)
- .sort().descending(Patient.NAME)
- .count(123)
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchAdv
+ // START SNIPPET: searchComposite
+ response = client.search()
+ .forResource("Observation")
+ .where(Observation.CODE_VALUE_DATE
+ .withLeft(Observation.CODE.exactly().code("FOO$BAR"))
+ .withRight(Observation.VALUE_DATE.exactly().day("2001-01-01")))
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: searchComposite
+ }
+ {
+ // START SNIPPET: transaction
+ List resources = new ArrayList();
+ // .. populate this list - note that you can also pass in a populated
+ // Bundle if you want to create one manually ..
- // START SNIPPET: searchPost
- response = client.search()
- .forResource("Patient")
- .where(Patient.NAME.matches().value("Tester"))
- .usingStyle(SearchStyleEnum.POST)
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchPost
+ List response = client.transaction().withResources(resources).execute();
+ // END SNIPPET: transaction
+ }
- // START SNIPPET: searchComposite
- response = client.search()
- .forResource("Observation")
- .where(Observation.CODE_VALUE_DATE
- .withLeft(Observation.CODE.exactly().code("FOO$BAR"))
- .withRight(Observation.VALUE_DATE.exactly().day("2001-01-01")))
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: searchComposite
- }
- {
- // START SNIPPET: transaction
- List resources = new ArrayList();
- // .. populate this list - note that you can also pass in a populated
- // Bundle if you want to create one manually ..
+ {
+ // START SNIPPET: read
+ // search for patient 123
+ Patient patient = client.read()
+ .resource(Patient.class)
+ .withId("123")
+ .execute();
+ // END SNIPPET: read
+ }
+ {
+ // START SNIPPET: vread
+ // search for patient 123 (specific version 888)
+ Patient patient = client.read()
+ .resource(Patient.class)
+ .withIdAndVersion("123", "888")
+ .execute();
+ // END SNIPPET: vread
+ }
+ {
+ // START SNIPPET: readabsolute
+ // search for patient 123 on example.com
+ String url = "http://example.com/fhir/Patient/123";
+ Patient patient = client.read()
+ .resource(Patient.class)
+ .withUrl(url)
+ .execute();
+ // END SNIPPET: readabsolute
+ }
+
+ {
+ // START SNIPPET: etagread
+ // search for patient 123
+ Patient patient = client.read()
+ .resource(Patient.class)
+ .withId("123")
+ .ifVersionMatches("001").returnNull()
+ .execute();
+ if (patient == null) {
+ // resource has not changed
+ }
+ // END SNIPPET: etagread
+ }
+
+
+
+ }
- List response = client.transaction().withResources(resources).execute();
- // END SNIPPET: transaction
- }
-
- {
- // START SNIPPET: read
- // search for patient 123
- Patient patient = client.read()
- .resource(Patient.class)
- .withId("123")
- .execute();
- // END SNIPPET: read
- }
- {
- // START SNIPPET: vread
- // search for patient 123 (specific version 888)
- Patient patient = client.read()
- .resource(Patient.class)
- .withIdAndVersion("123", "888")
- .execute();
- // END SNIPPET: vread
- }
- {
- // START SNIPPET: readabsolute
- // search for patient 123 on example.com
- String url = "http://example.com/fhir/Patient/123";
- Patient patient = client.read()
- .resource(Patient.class)
- .withUrl(url)
- .execute();
- // END SNIPPET: readabsolute
- }
-
- {
- // START SNIPPET: etagread
- // search for patient 123
- Patient patient = client.read()
- .resource(Patient.class)
- .withId("123")
- .ifVersionMatches("001").returnNull()
- .execute();
- if (patient == null) {
- // resource has not changed
- }
- // END SNIPPET: etagread
- }
-
-
- }
-
- @SuppressWarnings("unused")
- public static void history() {
- IGenericClient client = FhirContext.forDstu2().newRestfulGenericClient("");
- {
- // START SNIPPET: historyDstu2
+ @SuppressWarnings("unused")
+ public static void history() {
+ IGenericClient client = FhirContext.forDstu2().newRestfulGenericClient("");
+ {
+ // START SNIPPET: historyDstu2
Bundle response = client
- .history()
- .onServer()
- .returnBundle(Bundle.class)
- .execute();
- // END SNIPPET: historyDstu2
- }
- {
- // START SNIPPET: historyFeatures
+ .history()
+ .onServer()
+ .returnBundle(Bundle.class)
+ .execute();
+ // END SNIPPET: historyDstu2
+ }
+ {
+ // START SNIPPET: historyFeatures
Bundle response = client
- .history()
- .onServer()
- .returnBundle(Bundle.class)
- .since(new InstantType("2012-01-01T12:22:32.038Z"))
- .count(100)
- .execute();
- // END SNIPPET: historyFeatures
- }
- }
+ .history()
+ .onServer()
+ .returnBundle(Bundle.class)
+ .since(new InstantType("2012-01-01T12:22:32.038Z"))
+ .count(100)
+ .execute();
+ // END SNIPPET: historyFeatures
+ }
+ }
+
+ public static void main(String[] args) {
+ paging();
+ }
+ private static void paging() {
+ {
+ // START SNIPPET: searchPaging
+ FhirContext ctx = FhirContext.forDstu2();
+ IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
+
+ // Perform a search
+ Bundle resultBundle = client.search()
+ .forResource(Patient.class)
+ .where(Patient.NAME.matches().value("Smith"))
+ .returnBundle(Bundle.class)
+ .execute();
+
+ if (resultBundle.getLink(Bundle.LINK_NEXT) != null) {
- public static void main(String[] args) {
- paging();
- }
+ // load next page
+ Bundle nextPage = client.loadPage().next(resultBundle).execute();
+ }
+ // END SNIPPET: searchPaging
+ }
+ }
- private static void paging() {
- {
- // START SNIPPET: searchPaging
- FhirContext ctx = FhirContext.forDstu2();
- IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu2");
+ @SuppressWarnings("unused")
+ private static void operationHttpGet() {
+ // START SNIPPET: operationHttpGet
+ // Create a client to talk to the HeathIntersections server
+ FhirContext ctx = FhirContext.forDstu2();
+ IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
+ client.registerInterceptor(new LoggingInterceptor(true));
+
+ // Create the input parameters to pass to the server
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
+ inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
+
+ // Invoke $everything on "Patient/1"
+ Parameters outParams = client
+ .operation()
+ .onInstance(new IdType("Patient", "1"))
+ .named("$everything")
+ .withParameters(inParams)
+ .useHttpGet() // Use HTTP GET instead of POST
+ .execute();
+ // END SNIPPET: operationHttpGet
+ }
- // Perform a search
- Bundle resultBundle = client.search()
- .forResource(Patient.class)
- .where(Patient.NAME.matches().value("Smith"))
- .returnBundle(Bundle.class)
- .execute();
+ @SuppressWarnings("unused")
+ private static void operation() {
+ // START SNIPPET: operation
+ // Create a client to talk to the HeathIntersections server
+ FhirContext ctx = FhirContext.forDstu2();
+ IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
+ client.registerInterceptor(new LoggingInterceptor(true));
+
+ // Create the input parameters to pass to the server
+ Parameters inParams = new Parameters();
+ inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
+ inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
+
+ // Invoke $everything on "Patient/1"
+ Parameters outParams = client
+ .operation()
+ .onInstance(new IdType("Patient", "1"))
+ .named("$everything")
+ .withParameters(inParams)
+ .execute();
+
+ /*
+ * Note that the $everything operation returns a Bundle instead
+ * of a Parameters resource. The client operation methods return a
+ * Parameters instance however, so HAPI creates a Parameters object
+ * with a single parameter containing the value.
+ */
+ Bundle responseBundle = (Bundle) outParams.getParameter().get(0).getResource();
+
+ // Print the response bundle
+ System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(responseBundle));
+ // END SNIPPET: operation
+ }
- if (resultBundle.getLink(Bundle.LINK_NEXT) != null) {
-
- // load next page
- Bundle nextPage = client.loadPage().next(resultBundle).execute();
- }
- // END SNIPPET: searchPaging
- }
- }
-
- @SuppressWarnings("unused")
- private static void operationHttpGet() {
- // START SNIPPET: operationHttpGet
- // Create a client to talk to the HeathIntersections server
- FhirContext ctx = FhirContext.forDstu2();
- IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
- client.registerInterceptor(new LoggingInterceptor(true));
-
- // Create the input parameters to pass to the server
- Parameters inParams = new Parameters();
- inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
- inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
-
- // Invoke $everything on "Patient/1"
- Parameters outParams = client
- .operation()
- .onInstance(new IdType("Patient", "1"))
- .named("$everything")
- .withParameters(inParams)
- .useHttpGet() // Use HTTP GET instead of POST
- .execute();
- // END SNIPPET: operationHttpGet
- }
-
- @SuppressWarnings("unused")
- private static void operation() {
- // START SNIPPET: operation
- // Create a client to talk to the HeathIntersections server
- FhirContext ctx = FhirContext.forDstu2();
- IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
- client.registerInterceptor(new LoggingInterceptor(true));
-
- // Create the input parameters to pass to the server
- Parameters inParams = new Parameters();
- inParams.addParameter().setName("start").setValue(new DateType("2001-01-01"));
- inParams.addParameter().setName("end").setValue(new DateType("2015-03-01"));
-
- // Invoke $everything on "Patient/1"
- Parameters outParams = client
- .operation()
- .onInstance(new IdType("Patient", "1"))
- .named("$everything")
- .withParameters(inParams)
- .execute();
-
- /*
- * Note that the $everything operation returns a Bundle instead
- * of a Parameters resource. The client operation methods return a
- * Parameters instance however, so HAPI creates a Parameters object
- * with a single parameter containing the value.
- */
- Bundle responseBundle = (Bundle) outParams.getParameter().get(0).getResource();
-
- // Print the response bundle
- System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(responseBundle));
- // END SNIPPET: operation
- }
-
- @SuppressWarnings("unused")
- private static void operationNoIn() {
- // START SNIPPET: operationNoIn
- // Create a client to talk to the HeathIntersections server
- FhirContext ctx = FhirContext.forDstu2();
- IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
- client.registerInterceptor(new LoggingInterceptor(true));
-
- // Invoke $everything on "Patient/1"
- Parameters outParams = client
- .operation()
- .onInstance(new IdType("Patient", "1"))
- .named("$everything")
- .withNoParameters(Parameters.class) // No input parameters
- .execute();
- // END SNIPPET: operationNoIn
- }
+ @SuppressWarnings("unused")
+ private static void operationNoIn() {
+ // START SNIPPET: operationNoIn
+ // Create a client to talk to the HeathIntersections server
+ FhirContext ctx = FhirContext.forDstu2();
+ IGenericClient client = ctx.newRestfulGenericClient("http://fhir-dev.healthintersections.com.au/open");
+ client.registerInterceptor(new LoggingInterceptor(true));
+
+ // Invoke $everything on "Patient/1"
+ Parameters outParams = client
+ .operation()
+ .onInstance(new IdType("Patient", "1"))
+ .named("$everything")
+ .withNoParameters(Parameters.class) // No input parameters
+ .execute();
+ // END SNIPPET: operationNoIn
+ }
}
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md
index 353249e9ff3..5cb269efb1d 100644
--- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md
@@ -209,22 +209,6 @@ FHIR also specifies a type of update called "conditional updates", where instead
**See Also:** See the description of [Update ETags](#update_etags) below for information on specifying a matching version in the client request.
-# Patch - Instance
-
-The PATCH operation can be used to modify a resource in place by supplying a delta
-
-The following example shows how to perform a patch using a [FHIR Patch](http://hl7.org/fhir/fhirpatch.html)
-
-```java
-{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|patchFhir}}
-```
-
-The following example shows how to perform a patch using a [JSON Patch](https://tools.ietf.org/html/rfc6902.)
-
-```java
-{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|patchJson}}
-```
-
# History - Server/Type/Instance
To retrieve the version history of all resources, or all resources of a given type, or of a specific instance of a resource, you call the [`history()`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IGenericClient.html#history()) method.
diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml
index 59d4b572847..29555e96b03 100644
--- a/hapi-fhir-jpaserver-base/pom.xml
+++ b/hapi-fhir-jpaserver-base/pom.xml
@@ -562,11 +562,6 @@
embedded-elasticsearch
2.10.0
-
- org.hl7.fhir.testcases
- fhir-test-cases
- test
-
com.github.ben-manes.caffeine
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
index 8a05171d576..e936542da8d 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
@@ -35,7 +35,6 @@ import ca.uhn.fhir.jpa.api.model.ExpungeOptions;
import ca.uhn.fhir.jpa.api.model.ExpungeOutcome;
import ca.uhn.fhir.jpa.delete.DeleteConflictService;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
-import ca.uhn.fhir.jpa.patch.FhirPatch;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.jpa.model.entity.BaseHasResource;
import ca.uhn.fhir.jpa.model.entity.BaseTag;
@@ -53,8 +52,8 @@ import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.util.JpaInterceptorBroadcaster;
-import ca.uhn.fhir.jpa.patch.JsonPatchUtils;
-import ca.uhn.fhir.jpa.patch.XmlPatchUtils;
+import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils;
+import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.CacheControlDirective;
@@ -88,12 +87,10 @@ import ca.uhn.fhir.validation.IValidationContext;
import ca.uhn.fhir.validation.IValidatorModule;
import ca.uhn.fhir.validation.ValidationOptions;
import ca.uhn.fhir.validation.ValidationResult;
-import com.github.fge.jsonpatch.JsonPatch;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
-import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
@@ -889,24 +886,10 @@ public abstract class BaseHapiFhirResourceDao extends B
IBaseResource resourceToUpdate = toResource(entityToUpdate, false);
IBaseResource destination;
- switch (thePatchType) {
- case JSON_PATCH:
+ if (thePatchType == PatchTypeEnum.JSON_PATCH) {
destination = JsonPatchUtils.apply(getContext(), resourceToUpdate, thePatchBody);
- break;
- case XML_PATCH:
+ } else {
destination = XmlPatchUtils.apply(getContext(), resourceToUpdate, thePatchBody);
- break;
- case FHIR_PATCH_XML:
- IBaseParameters fhirPatchJson = (IBaseParameters) getContext().newXmlParser().parseResource(thePatchBody);
- new FhirPatch(getContext()).apply(resourceToUpdate, fhirPatchJson);
- destination = resourceToUpdate;
- break;
- default:
- case FHIR_PATCH_JSON:
- IBaseParameters fhirPatchXml = (IBaseParameters) getContext().newJsonParser().parseResource(thePatchBody);
- new FhirPatch(getContext()).apply(resourceToUpdate, fhirPatchXml);
- destination = resourceToUpdate;
- break;
}
@SuppressWarnings("unchecked")
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/FhirPatch.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/FhirPatch.java
deleted file mode 100644
index 7102366fe46..00000000000
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/FhirPatch.java
+++ /dev/null
@@ -1,316 +0,0 @@
-package ca.uhn.fhir.jpa.patch;
-
-import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
-import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
-import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
-import ca.uhn.fhir.util.IModelVisitor2;
-import ca.uhn.fhir.util.ParametersUtil;
-import org.apache.commons.lang3.Validate;
-import org.hl7.fhir.instance.model.api.IBase;
-import org.hl7.fhir.instance.model.api.IBaseEnumeration;
-import org.hl7.fhir.instance.model.api.IBaseExtension;
-import org.hl7.fhir.instance.model.api.IBaseParameters;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.instance.model.api.IPrimitiveType;
-import org.hl7.fhir.utilities.xhtml.XhtmlNode;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
-
-import static org.apache.commons.lang3.StringUtils.defaultString;
-import static org.apache.commons.lang3.StringUtils.isNotBlank;
-
-public class FhirPatch {
-
- private final FhirContext myContext;
-
- public FhirPatch(FhirContext theContext) {
- myContext = theContext;
- }
-
- public void apply(IBaseResource theResource, IBaseResource thePatch) {
-
- List opParameters = ParametersUtil.getNamedParameters(myContext, thePatch, "operation");
- for (IBase nextOp : opParameters) {
- String type = ParametersUtil.getParameterPartValueAsString(myContext, nextOp, "type");
- String path = ParametersUtil.getParameterPartValueAsString(myContext, nextOp, "path");
- Optional valuePart = ParametersUtil.getParameterPart(myContext, nextOp, "value");
- Optional valuePartValue = ParametersUtil.getParameterPartValue(myContext, nextOp, "value");
-
- type = defaultString(type);
- path = defaultString(path);
-
- String containingPath;
- String elementName;
- Integer removeIndex = null;
- Integer insertIndex = null;
- if ("delete".equals(type)) {
-
- doDelete(theResource, path);
- return;
-
- } else if ("add".equals(type)) {
-
- containingPath = path;
- elementName = ParametersUtil.getParameterPartValueAsString(myContext, nextOp, "name");
-
- } else if ("replace".equals(type)) {
-
- int lastDot = path.lastIndexOf(".");
- containingPath = path.substring(0, lastDot);
- elementName = path.substring(lastDot + 1);
-
- } else if ("insert".equals(type)) {
-
- int lastDot = path.lastIndexOf(".");
- containingPath = path.substring(0, lastDot);
- elementName = path.substring(lastDot + 1);
- insertIndex = ParametersUtil
- .getParameterPartValue(myContext, nextOp, "index")
- .map(t -> (IPrimitiveType) t)
- .map(t -> t.getValue())
- .orElseThrow(() -> new InvalidRequestException("No index supplied for insert operation"));
-
- } else if ("move".equals(type)) {
-
- int lastDot = path.lastIndexOf(".");
- containingPath = path.substring(0, lastDot);
- elementName = path.substring(lastDot + 1);
- insertIndex = ParametersUtil
- .getParameterPartValue(myContext, nextOp, "destination")
- .map(t -> (IPrimitiveType) t)
- .map(t -> t.getValue())
- .orElseThrow(() -> new InvalidRequestException("No index supplied for insert operation"));
- removeIndex = ParametersUtil
- .getParameterPartValue(myContext, nextOp, "source")
- .map(t -> (IPrimitiveType) t)
- .map(t -> t.getValue())
- .orElseThrow(() -> new InvalidRequestException("No index supplied for insert operation"));
-
- } else {
-
- throw new InvalidRequestException("Unknown patch operation type: " + type);
-
- }
-
- List paths = myContext.newFhirPath().evaluate(theResource, containingPath, IBase.class);
- for (IBase next : paths) {
-
- BaseRuntimeElementCompositeDefinition> element = (BaseRuntimeElementCompositeDefinition>) myContext.getElementDefinition(next.getClass());
- String childName = elementName;
- BaseRuntimeChildDefinition childDef = element.getChildByName(childName);
- BaseRuntimeElementDefinition> childElement;
- if (childDef == null) {
- childName = elementName + "[x]";
- childDef = element.getChildByName(childName);
- childElement = childDef.getChildByName(childDef.getValidChildNames().iterator().next());
- } else {
- childElement = childDef.getChildByName(childName);
- }
-
- if ("move".equals(type)) {
-
- List existingValues = new ArrayList<>(childDef.getAccessor().getValues(next));
- if (removeIndex >= existingValues.size()) {
- String msg = myContext.getLocalizer().getMessage(FhirPatch.class, "invalidMoveSourceIndex", removeIndex, path, existingValues.size());
- throw new InvalidRequestException(msg);
- }
- IBase newValue = existingValues.remove(removeIndex.intValue());
-
- if (insertIndex > existingValues.size()) {
- String msg = myContext.getLocalizer().getMessage(FhirPatch.class, "invalidMoveDestinationIndex", insertIndex, path, existingValues.size());
- throw new InvalidRequestException(msg);
- }
- existingValues.add(insertIndex, newValue);
-
- childDef.getMutator().setValue(next, null);
- for (IBase nextNewValue : existingValues) {
- childDef.getMutator().addValue(next, nextNewValue);
- }
-
- continue;
- }
-
- IBase newValue;
- if (valuePartValue.isPresent()) {
- newValue = valuePartValue.get();
- } else {
- newValue = childElement.newInstance();
-
- if (valuePart.isPresent()) {
- List valuePartParts = myContext.newTerser().getValues(valuePart.get(), "part");
- for (IBase nextValuePartPart : valuePartParts) {
-
- String name = myContext.newTerser().getSingleValue(nextValuePartPart, "name", IPrimitiveType.class).map(t -> t.getValueAsString()).orElse(null);
- if (isNotBlank(name)) {
-
- Optional value = myContext.newTerser().getSingleValue(nextValuePartPart, "value[x]", IBase.class);
- if (value.isPresent()) {
-
- BaseRuntimeChildDefinition partChildDef = ((BaseRuntimeElementCompositeDefinition>) childElement).getChildByName(name);
- partChildDef.getMutator().addValue(newValue, value.get());
-
- }
-
- }
-
- }
- }
-
- }
-
- if (IBaseEnumeration.class.isAssignableFrom(childElement.getImplementingClass()) || XhtmlNode.class.isAssignableFrom(childElement.getImplementingClass())) {
- // If the element is an IBaseEnumeration, we will use the actual element definition to build one, since
- // it needs the right factory object passed to its constructor
- IPrimitiveType> newValueInstance = (IPrimitiveType>) childElement.newInstance();
- newValueInstance.setValueAsString(((IPrimitiveType>) newValue).getValueAsString());
- childDef.getMutator().setValue(next, newValueInstance);
- newValue = newValueInstance;
- }
-
- if ("insert".equals(type)) {
-
- List existingValues = new ArrayList<>(childDef.getAccessor().getValues(next));
- if (insertIndex > existingValues.size()) {
- String msg = myContext.getLocalizer().getMessage(FhirPatch.class, "invalidInsertIndex", insertIndex, path, existingValues.size());
- throw new InvalidRequestException(msg);
- }
- existingValues.add(insertIndex, newValue);
-
- childDef.getMutator().setValue(next, null);
- for (IBase nextNewValue : existingValues) {
- childDef.getMutator().addValue(next, nextNewValue);
- }
-
- } else {
- childDef.getMutator().setValue(next, newValue);
- }
-
- }
-
-
- }
-
- }
-
-
- public void doDelete(IBaseResource theResource, String thePath) {
- List paths = myContext.newFhirPath().evaluate(theResource, thePath, IBase.class);
- for (IBase next : paths) {
- myContext.newTerser().visit(next, new IModelVisitor2() {
- @Override
- public boolean acceptElement(IBase theElement, List theContainingElementPath, List theChildDefinitionPath, List> theElementDefinitionPath) {
- if (theElement instanceof IPrimitiveType) {
- ((IPrimitiveType>) theElement).setValueAsString(null);
- }
- return true;
- }
-
- @Override
- public boolean acceptUndeclaredExtension(IBaseExtension, ?> theNextExt, List theContainingElementPath, List theChildDefinitionPath, List> theElementDefinitionPath) {
- theNextExt.setUrl(null);
- theNextExt.setValue(null);
- return true;
- }
- });
- }
- }
-
- public IBaseParameters diff(IBaseResource theOldValue, IBaseResource theNewValue) {
- String oldValueTypeName = myContext.getResourceDefinition(theOldValue).getName();
- String newValueTypeName = myContext.getResourceDefinition(theNewValue).getName();
- Validate.isTrue(oldValueTypeName.equalsIgnoreCase(newValueTypeName), "Resources must be of same type");
-
- IBaseParameters retVal = ParametersUtil.newInstance(myContext);
-
- BaseRuntimeElementCompositeDefinition> def = myContext.getResourceDefinition(theOldValue).getBaseDefinition();
- String path = def.getName();
-
- compare(retVal, def, path, path, theOldValue, theNewValue);
-
- return retVal;
- }
-
- public void compare(IBaseParameters theDiff, BaseRuntimeElementDefinition> theDef, String theSourcePath, String theTargetPath, IBase theOldField, IBase theNewField) {
-
- if (theDef instanceof BaseRuntimeElementCompositeDefinition) {
-
- for (BaseRuntimeChildDefinition nextChild : ((BaseRuntimeElementCompositeDefinition>) theDef).getChildren()) {
-
- List sourceValues = nextChild.getAccessor().getValues(theOldField);
- List targetValues = nextChild.getAccessor().getValues(theNewField);
-
- int sourceIndex = 0;
- int targetIndex = 0;
- while (sourceIndex < sourceValues.size() && targetIndex < targetValues.size()) {
-
- IBase sourceChildField = sourceValues.get(sourceIndex);
- Validate.notNull(sourceChildField); // not expected to happen, but just in case
- BaseRuntimeElementDefinition> def = myContext.getElementDefinition(sourceChildField.getClass());
- IBase targetChildField = targetValues.get(targetIndex);
- Validate.notNull(targetChildField); // not expected to happen, but just in case
- String sourcePath = theSourcePath + "." + nextChild.getElementName() + (nextChild.getMax() != 1 ? "[" + sourceIndex + "]" : "");
- String targetPath = theSourcePath + "." + nextChild.getElementName() + (nextChild.getMax() != 1 ? "[" + targetIndex + "]" : "");
-
- compare(theDiff, def, sourcePath, targetPath, sourceChildField, targetChildField);
-
- sourceIndex++;
- targetIndex++;
- }
-
- // Find newly inserted items
- while (targetIndex < targetValues.size()) {
- IBase operation = ParametersUtil.addParameterToParameters(myContext, theDiff, "operation");
- ParametersUtil.addPartCode(myContext, operation, "type", "insert");
- ParametersUtil.addPartString(myContext, operation, "path", theTargetPath + "." + nextChild.getElementName());
- ParametersUtil.addPartInteger(myContext, operation, "index", targetIndex);
- ParametersUtil.addPart(myContext, operation, "value", targetValues.get(targetIndex));
-
- targetIndex++;
- }
-
- // Find deleted items
- while (sourceIndex < sourceValues.size()) {
- IBase operation = ParametersUtil.addParameterToParameters(myContext, theDiff, "operation");
- ParametersUtil.addPartCode(myContext, operation, "type", "delete");
- ParametersUtil.addPartString(myContext, operation, "path", theTargetPath + "." + nextChild.getElementName() + (nextChild.getMax() != 1 ? "[" + targetIndex + "]" : ""));
-
- sourceIndex++;
- targetIndex++;
- }
-
- }
-
- } else {
-
- BaseRuntimeElementDefinition> sourceDef = myContext.getElementDefinition(theOldField.getClass());
- BaseRuntimeElementDefinition> targetDef = myContext.getElementDefinition(theNewField.getClass());
- if (!sourceDef.getName().equals(targetDef.getName())) {
- IBase operation = ParametersUtil.addParameterToParameters(myContext, theDiff, "operation");
- ParametersUtil.addPartCode(myContext, operation, "type", "replace");
- ParametersUtil.addPartString(myContext, operation, "path", theTargetPath);
- ParametersUtil.addPart(myContext, operation, "value", theNewField);
- } else if (theOldField instanceof IPrimitiveType) {
- IPrimitiveType> oldPrimitive = (IPrimitiveType>) theOldField;
- IPrimitiveType> newPrimitive = (IPrimitiveType>) theNewField;
- if (!Objects.equals(oldPrimitive.getValueAsString(), newPrimitive.getValueAsString())) {
- IBase operation = ParametersUtil.addParameterToParameters(myContext, theDiff, "operation");
- ParametersUtil.addPartCode(myContext, operation, "type", "replace");
- ParametersUtil.addPartString(myContext, operation, "path", theTargetPath);
- ParametersUtil.addPart(myContext, operation, "value", newPrimitive);
- }
-
- if ()
-
-
- }
-
- }
-
- }
-
-}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/JsonPatchUtils.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtils.java
similarity index 98%
rename from hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/JsonPatchUtils.java
rename to hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtils.java
index 51ffa794016..516f7eb617a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/JsonPatchUtils.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtils.java
@@ -1,4 +1,4 @@
-package ca.uhn.fhir.jpa.patch;
+package ca.uhn.fhir.jpa.util.jsonpatch;
/*
* #%L
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/xmlpatch/XmlPatchUtils.java
similarity index 97%
rename from hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java
rename to hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/xmlpatch/XmlPatchUtils.java
index b8ae5b28d61..1716f0976d1 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/patch/XmlPatchUtils.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/xmlpatch/XmlPatchUtils.java
@@ -1,4 +1,4 @@
-package ca.uhn.fhir.jpa.patch;
+package ca.uhn.fhir.jpa.util.xmlpatch;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.Constants;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/BaseFhirPatchCoreTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/BaseFhirPatchCoreTest.java
deleted file mode 100644
index e7ee5f14f27..00000000000
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/BaseFhirPatchCoreTest.java
+++ /dev/null
@@ -1,115 +0,0 @@
-package ca.uhn.fhir.jpa.patch;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.test.BaseTest;
-import ca.uhn.fhir.util.ClasspathUtil;
-import ca.uhn.fhir.util.XmlUtil;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.r4.model.Parameters;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import javax.annotation.Nonnull;
-import javax.xml.transform.TransformerException;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.fail;
-
-@RunWith(Parameterized.class)
-public abstract class BaseFhirPatchCoreTest extends BaseTest {
-
- private static final Logger ourLog = LoggerFactory.getLogger(BaseFhirPatchCoreTest.class);
- private final String myName;
- private final String myMode;
- private final IBaseResource myInput;
- private final IBaseResource myPatch;
- private final IBaseResource myOutput;
-
- public BaseFhirPatchCoreTest(String theName, String theMode, IBaseResource theInput, IBaseResource thePatch, IBaseResource theOutput) {
- myName = theName;
- myMode = theMode;
- myInput = theInput;
- myPatch = thePatch;
- myOutput = theOutput;
- }
-
- @Test
- public void testApply() {
- ourLog.info("Testing diff in {} mode: {}", myMode, myName);
-
- if (myMode.equals("both") || myMode.equals("forwards")) {
-
- FhirPatch patch = new FhirPatch(getContext());
- patch.apply(myInput, myPatch);
-
- String expected = getContext().newJsonParser().setPrettyPrint(true).encodeResourceToString(myOutput);
- String actual = getContext().newJsonParser().setPrettyPrint(true).encodeResourceToString(myInput);
- assertEquals(expected, actual);
-
- } else {
- fail("Unknown mode: " + myMode);
- }
-
- }
-
- protected abstract FhirContext getContext();
-
-
- @Nonnull
- public static Collection loadTestSpec(FhirContext theContext, String theTestSpec) throws IOException, SAXException, TransformerException {
- List retVal = new ArrayList<>();
-
- String testsString = ClasspathUtil.loadResource(theTestSpec);
- Document doc = XmlUtil.parseDocument(testsString);
- Element tests = (Element) doc.getElementsByTagName("tests").item(0);
- NodeList cases = tests.getElementsByTagName("case");
-
- for (int i = 0; i < cases.getLength(); i++) {
- Element next = (Element) cases.item(i);
-
- String name = next.getAttribute("name");
- String mode = next.getAttribute("mode");
-
- Element diffElement = (Element) next.getElementsByTagName("diff").item(0);
- Element diffParametersElement = getFirstChildElement(diffElement);
- String encoded = XmlUtil.encodeDocument(diffParametersElement);
- IBaseResource diff = theContext.newXmlParser().parseResource(encoded);
-
- Element inputElement = (Element) next.getElementsByTagName("input").item(0);
- Element inputResourceElement = getFirstChildElement(inputElement);
- String inputEncoded = XmlUtil.encodeDocument(inputResourceElement);
- IBaseResource input = theContext.newXmlParser().parseResource(inputEncoded);
-
- Element outputElement = (Element) next.getElementsByTagName("output").item(0);
- Element outputResourceElement = getFirstChildElement(outputElement);
- String outputEncoded = XmlUtil.encodeDocument(outputResourceElement);
- IBaseResource output = theContext.newXmlParser().parseResource(outputEncoded);
-
- retVal.add(new Object[]{name, mode, input, diff, output});
-
- }
-
- return retVal;
- }
-
- private static Element getFirstChildElement(Element theInput) {
- for (int i = 0; i < theInput.getChildNodes().getLength(); i++) {
- if (theInput.getChildNodes().item(i) instanceof Element) {
- return (Element) theInput.getChildNodes().item(i);
- }
- }
- fail("No child of type Element");
- throw new Error();
- }
-}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4CoreTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4CoreTest.java
deleted file mode 100644
index 419b263fce7..00000000000
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4CoreTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package ca.uhn.fhir.jpa.patch;
-
-import ca.uhn.fhir.context.FhirContext;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.xml.sax.SAXException;
-
-import javax.xml.transform.TransformerException;
-import java.io.IOException;
-import java.util.Collection;
-
-@RunWith(Parameterized.class)
-public class FhirPatchR4CoreTest extends BaseFhirPatchCoreTest {
-
- private static final FhirContext ourCtx = FhirContext.forR4();
-
- public FhirPatchR4CoreTest(String theName, String theMode, IBaseResource theInput, IBaseResource thePatch, IBaseResource theOutput) {
- super(theName, theMode, theInput, thePatch, theOutput);
- }
-
- @Override
- protected FhirContext getContext() {
- return ourCtx;
- }
-
- @Parameterized.Parameters(name = "{0}")
- public static Collection parameters() throws IOException, SAXException, TransformerException {
- String testSpec = "/org/hl7/fhir/testcases/r4/patch/fhir-path-tests.xml";
- return loadTestSpec(ourCtx, testSpec);
- }
-
-}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4Test.java
deleted file mode 100644
index bf86a393702..00000000000
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR4Test.java
+++ /dev/null
@@ -1,330 +0,0 @@
-package ca.uhn.fhir.jpa.patch;
-
-import ca.uhn.fhir.context.FhirContext;
-import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
-import org.hl7.fhir.instance.model.api.IBase;
-import org.hl7.fhir.instance.model.api.IPrimitiveType;
-import org.hl7.fhir.r4.model.BooleanType;
-import org.hl7.fhir.r4.model.CodeType;
-import org.hl7.fhir.r4.model.DateTimeType;
-import org.hl7.fhir.r4.model.Extension;
-import org.hl7.fhir.r4.model.Identifier;
-import org.hl7.fhir.r4.model.IntegerType;
-import org.hl7.fhir.r4.model.Parameters;
-import org.hl7.fhir.r4.model.Patient;
-import org.hl7.fhir.r4.model.StringType;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.stream.Collectors;
-
-import static org.junit.Assert.assertEquals;
-
-public class FhirPatchR4Test {
-
- private static final Logger ourLog = LoggerFactory.getLogger(FhirPatchR4Test.class);
- private static final FhirContext ourCtx = FhirContext.forR4();
-
- @Test
- public void testInvalidOperation() {
- FhirPatch svc = new FhirPatch(ourCtx);
-
- Patient patient = new Patient();
-
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("foo"));
-
- try {
- svc.apply(patient, patch);
- } catch (InvalidRequestException e) {
- assertEquals("Unknown patch operation type: foo", e.getMessage());
- }
- }
-
- @Test
- public void testInsertToInvalidIndex() {
- FhirPatch svc = new FhirPatch(ourCtx);
-
- Patient patient = new Patient();
-
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("insert"));
- operation
- .addPart()
- .setName("path")
- .setValue(new StringType("Patient.identifier"));
- operation
- .addPart()
- .setName("index")
- .setValue(new IntegerType(2));
-
- try {
- svc.apply(patient, patch);
- } catch (InvalidRequestException e) {
- assertEquals("Invalid insert index 2 for path Patient.identifier - Only have 0 existing entries", e.getMessage());
- }
- }
-
- @Test
- public void testMoveFromInvalidIndex() {
- FhirPatch svc = new FhirPatch(ourCtx);
-
- Patient patient = new Patient();
-
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("move"));
- operation
- .addPart()
- .setName("path")
- .setValue(new StringType("Patient.identifier"));
- operation
- .addPart()
- .setName("source")
- .setValue(new IntegerType(2));
- operation
- .addPart()
- .setName("destination")
- .setValue(new IntegerType(1));
-
- try {
- svc.apply(patient, patch);
- } catch (InvalidRequestException e) {
- assertEquals("Invalid move source index 2 for path Patient.identifier - Only have 0 existing entries", e.getMessage());
- }
- }
-
- @Test
- public void testMoveToInvalidIndex() {
- FhirPatch svc = new FhirPatch(ourCtx);
-
- Patient patient = new Patient();
- patient.addIdentifier().setSystem("sys");
-
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("move"));
- operation
- .addPart()
- .setName("path")
- .setValue(new StringType("Patient.identifier"));
- operation
- .addPart()
- .setName("source")
- .setValue(new IntegerType(0));
- operation
- .addPart()
- .setName("destination")
- .setValue(new IntegerType(1));
-
- try {
- svc.apply(patient, patch);
- } catch (InvalidRequestException e) {
- assertEquals("Invalid move destination index 1 for path Patient.identifier - Only have 0 existing entries", e.getMessage());
- }
- }
-
- @Test
- public void testDeleteItemWithExtension() {
- FhirPatch svc = new FhirPatch(ourCtx);
-
- Patient patient = new Patient();
- patient.setActive(true);
- patient.addIdentifier().addExtension("http://foo", new StringType("abc"));
- patient.addIdentifier().setSystem("sys").setValue("val");
-
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("delete"));
- operation
- .addPart()
- .setName("path")
- .setValue(new StringType("Patient.identifier[0]"));
-
- svc.apply(patient, patch);
-
- assertEquals("{\"resourceType\":\"Patient\",\"identifier\":[{\"system\":\"sys\",\"value\":\"val\"}],\"active\":true}", ourCtx.newJsonParser().encodeResourceToString(patient));
-
- }
-
- @Test
- public void testGeneratePatch_ReplaceIdentifier() {
- Patient oldValue = new Patient();
- oldValue.addIdentifier().setSystem("system-0").setValue("value-0");
-
- Patient newValue = new Patient();
- newValue.addIdentifier().setSystem("system-1").setValue("value-1");
-
- FhirPatch svc = new FhirPatch(ourCtx);
- Parameters diff = (Parameters) svc.diff(oldValue, newValue);
-
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(diff));
-
- assertEquals(2, diff.getParameter().size());
- assertEquals("replace", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("Patient.identifier[0].system", extractPartValuePrimitive(diff, 0, "operation", "path"));
- assertEquals("system-1", extractPartValuePrimitive(diff, 0, "operation", "value"));
- assertEquals("replace", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("Patient.identifier[0].value", extractPartValuePrimitive(diff, 1, "operation", "path"));
- assertEquals("value-1", extractPartValuePrimitive(diff, 1, "operation", "value"));
-
- validateDiffProducesSameResults(oldValue, newValue, svc, diff);
- }
-
- @Test
- public void testGeneratePatch_ReplaceChoice() {
- Patient oldValue = new Patient();
- oldValue.setDeceased(new BooleanType(true));
-
- Patient newValue = new Patient();
- newValue.setDeceased(new DateTimeType("2020-05-16"));
-
-
- FhirPatch svc = new FhirPatch(ourCtx);
- Parameters diff = (Parameters) svc.diff(oldValue, newValue);
-
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(diff));
-
- assertEquals(1, diff.getParameter().size());
- assertEquals("replace", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("Patient.deceased", extractPartValuePrimitive(diff, 0, "operation", "path"));
- assertEquals("2020-05-16", extractPartValuePrimitive(diff, 0, "operation", "value"));
-
- validateDiffProducesSameResults(oldValue, newValue, svc, diff);
- }
-
- @Test
- public void testGeneratePatch_ReplaceChoice2() {
- Patient oldValue = new Patient();
- oldValue.setDeceased(new DateTimeType("2020-05-16"));
-
- Patient newValue = new Patient();
- newValue.setDeceased(new BooleanType(true));
-
-
- FhirPatch svc = new FhirPatch(ourCtx);
- Parameters diff = (Parameters) svc.diff(oldValue, newValue);
-
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(diff));
-
- assertEquals(1, diff.getParameter().size());
- assertEquals("replace", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("Patient.deceased", extractPartValuePrimitive(diff, 0, "operation", "path"));
- assertEquals("true", extractPartValuePrimitive(diff, 0, "operation", "value"));
-
- validateDiffProducesSameResults(oldValue, newValue, svc, diff);
- }
-
- @Test
- public void testGeneratePatch_AddExtensionOnPrimitive() {
- Patient oldValue = new Patient();
- oldValue.setActive(true);
-
- Patient newValue = new Patient();
- newValue.setActive(true);
- newValue.getActiveElement().addExtension("http://foo", new StringType("a value"));
-
- FhirPatch svc = new FhirPatch(ourCtx);
- Parameters diff = (Parameters) svc.diff(oldValue, newValue);
-
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(diff));
-
- assertEquals(1, diff.getParameter().size());
- assertEquals("insert", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("Patient.active.extension", extractPartValuePrimitive(diff, 0, "operation", "path"));
- assertEquals("0", extractPartValuePrimitive(diff, 0, "operation", "index"));
- assertEquals("http://foo", extractPartValue(diff, 0, "operation", "value", Extension.class).getUrl());
- assertEquals("a value", extractPartValue(diff, 0, "operation", "value", Extension.class).getValueAsPrimitive().getValueAsString());
-
- validateDiffProducesSameResults(oldValue, newValue, svc, diff);
- }
-
- @Test
- public void testGeneratePatch_InsertIdentifier() {
- Patient oldValue = new Patient();
- oldValue.addIdentifier().setSystem("system-0").setValue("value-0");
-
- Patient newValue = new Patient();
- newValue.addIdentifier().setSystem("system-0").setValue("value-0");
- newValue.addIdentifier().setSystem("system-1").setValue("value-1");
-
- FhirPatch svc = new FhirPatch(ourCtx);
- Parameters diff = (Parameters) svc.diff(oldValue, newValue);
-
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(diff));
-
- assertEquals(1, diff.getParameter().size());
- assertEquals("insert", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("1", extractPartValuePrimitive(diff, 0, "operation", "index"));
- assertEquals("Patient.identifier", extractPartValuePrimitive(diff, 0, "operation", "path"));
- assertEquals("system-1", extractPartValue(diff, 0, "operation", "value", Identifier.class).getSystem());
- assertEquals("value-1", extractPartValue(diff, 0, "operation", "value", Identifier.class).getValue());
-
- validateDiffProducesSameResults(oldValue, newValue, svc, diff);
- }
-
- @Test
- public void testGeneratePatch_DeleteIdentifier() {
- Patient oldValue = new Patient();
- oldValue.addIdentifier().setSystem("system-0").setValue("value-0");
- oldValue.addIdentifier().setSystem("system-1").setValue("value-1");
-
- Patient newValue = new Patient();
- newValue.addIdentifier().setSystem("system-0").setValue("value-0");
-
- FhirPatch svc = new FhirPatch(ourCtx);
- Parameters diff = (Parameters) svc.diff(oldValue, newValue);
-
- ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(diff));
-
- assertEquals(1, diff.getParameter().size());
- assertEquals("delete", extractPartValuePrimitive(diff, 0, "operation", "type"));
- assertEquals("Patient.identifier[1]", extractPartValuePrimitive(diff, 0, "operation", "path"));
-
- validateDiffProducesSameResults(oldValue, newValue, svc, diff);
- }
-
- public void validateDiffProducesSameResults(Patient theOldValue, Patient theNewValue, FhirPatch theSvc, Parameters theDiff) {
- theSvc.apply(theOldValue, theDiff);
- String expected = ourCtx.newJsonParser().encodeResourceToString(theNewValue);
- String actual = ourCtx.newJsonParser().encodeResourceToString(theOldValue);
- assertEquals(expected, actual);
- }
-
- public String extractPartValuePrimitive(Parameters theDiff, int theIndex, String theParameterName, String thePartName) {
- Parameters.ParametersParameterComponent component = theDiff.getParameter().stream().filter(t -> t.getName().equals(theParameterName)).collect(Collectors.toList()).get(theIndex);
- Parameters.ParametersParameterComponent part = component.getPart().stream().filter(t -> t.getName().equals(thePartName)).findFirst().orElseThrow(() -> new IllegalArgumentException());
- return ((IPrimitiveType) part.getValue()).getValueAsString();
- }
-
- public T extractPartValue(Parameters theDiff, int theIndex, String theParameterName, String thePartName, Class theExpectedType) {
- Parameters.ParametersParameterComponent component = theDiff.getParameter().stream().filter(t -> t.getName().equals(theParameterName)).collect(Collectors.toList()).get(theIndex);
- Parameters.ParametersParameterComponent part = component.getPart().stream().filter(t -> t.getName().equals(thePartName)).findFirst().orElseThrow(() -> new IllegalArgumentException());
- assert theExpectedType.isAssignableFrom(part.getValue().getClass());
- return (T) part.getValue();
- }
-
-}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR5CoreTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR5CoreTest.java
deleted file mode 100644
index 67dfbdb643d..00000000000
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/patch/FhirPatchR5CoreTest.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package ca.uhn.fhir.jpa.patch;
-
-import ca.uhn.fhir.context.FhirContext;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.xml.sax.SAXException;
-
-import javax.xml.transform.TransformerException;
-import java.io.IOException;
-import java.util.Collection;
-
-@RunWith(Parameterized.class)
-public class FhirPatchR5CoreTest extends BaseFhirPatchCoreTest {
-
- private static final FhirContext ourCtx = FhirContext.forR5();
-
- public FhirPatchR5CoreTest(String theName, String theMode, IBaseResource theInput, IBaseResource thePatch, IBaseResource theOutput) {
- super(theName, theMode, theInput, thePatch, theOutput);
- }
-
- @Override
- protected FhirContext getContext() {
- return ourCtx;
- }
-
- @Parameterized.Parameters(name = "{0}")
- public static Collection parameters() throws IOException, SAXException, TransformerException {
- String testSpec = "/org/hl7/fhir/testcases/r5/patch/fhir-path-tests.xml";
- return loadTestSpec(ourCtx, testSpec);
- }
-
-}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatchProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatchProviderR4Test.java
index d8f72d34686..60c65528c52 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatchProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/PatchProviderR4Test.java
@@ -1,7 +1,6 @@
package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.rest.api.Constants;
-import ca.uhn.fhir.rest.api.MethodOutcome;
import com.google.common.base.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
@@ -9,7 +8,6 @@ import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
-import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.*;
import org.junit.Test;
@@ -28,39 +26,6 @@ public class PatchProviderR4Test extends BaseResourceProviderR4Test {
private static final Logger ourLog = LoggerFactory.getLogger(PatchProviderR4Test.class);
- @Test
- public void testFhirPatch() {
- Patient patient = new Patient();
- patient.setActive(true);
- patient.addIdentifier().addExtension("http://foo", new StringType("abc"));
- patient.addIdentifier().setSystem("sys").setValue("val");
- IIdType id = ourClient.create().resource(patient).execute().getId().toUnqualifiedVersionless();
-
- Parameters patch = new Parameters();
- Parameters.ParametersParameterComponent operation = patch.addParameter();
- operation.setName("operation");
- operation
- .addPart()
- .setName("type")
- .setValue(new CodeType("delete"));
- operation
- .addPart()
- .setName("path")
- .setValue(new StringType("Patient.identifier[0]"));
-
- MethodOutcome outcome = ourClient
- .patch()
- .withFhirPatch(patch)
- .withId(id)
- .execute();
-
- Patient resultingResource = (Patient) outcome.getResource();
- assertEquals(1, resultingResource.getIdentifier().size());
-
- resultingResource = ourClient.read().resource(Patient.class).withId(id).execute();
- assertEquals(1, resultingResource.getIdentifier().size());
- }
-
@Test
public void testPatchAddArray() throws IOException {
IIdType id;
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtilsTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtilsTest.java
index 944ecfe8a43..749b39dde90 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtilsTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/util/jsonpatch/JsonPatchUtilsTest.java
@@ -2,7 +2,6 @@ package ca.uhn.fhir.jpa.util.jsonpatch;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
-import ca.uhn.fhir.jpa.patch.JsonPatchUtils;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.r4.model.Observation;
import org.junit.Test;
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/PatchTypeParameter.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/PatchTypeParameter.java
index 363efb05c30..45e087b7582 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/PatchTypeParameter.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/PatchTypeParameter.java
@@ -1,7 +1,6 @@
package ca.uhn.fhir.rest.server.method;
import static org.apache.commons.lang3.StringUtils.defaultString;
-import static org.apache.commons.lang3.StringUtils.trim;
/*
* #%L
@@ -46,14 +45,6 @@ class PatchTypeParameter implements IParameter {
public static PatchTypeEnum getTypeForRequestOrThrowInvalidRequestException(RequestDetails theRequest) {
String contentTypeAll = defaultString(theRequest.getHeader(Constants.HEADER_CONTENT_TYPE));
-
- int semicolonIndex = contentTypeAll.indexOf(';');
- if (semicolonIndex > 0) {
- contentTypeAll = contentTypeAll.substring(0, semicolonIndex);
- }
-
- contentTypeAll = trim(contentTypeAll);
-
return PatchTypeEnum.forContentTypeOrThrowInvalidRequestException(contentTypeAll);
}
diff --git a/pom.xml b/pom.xml
index ff7befaf766..593c4c067f5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -870,11 +870,6 @@
commons-csv
1.7
-
- org.hl7.fhir.testcases
- fhir-test-cases
- 1.1.14-SNAPSHOT
-
org.jetbrains
annotations