diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ConditionalUrlParam.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ConditionalUrlParam.java
index 2183f18813d..a4778fbbf05 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ConditionalUrlParam.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/annotation/ConditionalUrlParam.java
@@ -31,6 +31,9 @@ import java.lang.annotation.Target;
* conditional "search" URL for the operation, if an incoming client invocation is
* a conditional operation. For non-conditional invocations, the value will be set to
* null
so it is important to handle null
.
+ *
+ * Parameters annotated with this annotation must be of type {@link String}
+ *
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java
index 500dbda10d8..1d96e2c88e6 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/method/ConditionalParamBinder.java
@@ -29,7 +29,9 @@ import java.util.Map;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
+import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@@ -48,7 +50,9 @@ class ConditionalParamBinder implements IParameter {
@Override
public void initializeTypes(Method theMethod, Class extends Collection>> theOuterCollectionType, Class extends Collection>> theInnerCollectionType, Class> theParameterType) {
- // nothing
+ if (theOuterCollectionType != null || theInnerCollectionType != null || theParameterType.equals(String.class) == false) {
+ throw new ConfigurationException("Parameters annotated with @" + ConditionalUrlParam.class.getSimpleName() + " must be of type String, found incorrect parameteter in method \"" + theMethod + "\"");
+ }
}
public boolean isSupportsMultiple() {
@@ -57,7 +61,7 @@ class ConditionalParamBinder implements IParameter {
@Override
public void translateClientArgumentIntoQueryArgument(FhirContext theContext, Object theSourceClientArgument, Map> theTargetQueryArguments, IBaseResource theTargetResource) throws InternalErrorException {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException("Can not use @" + getClass().getName() + " annotated parameters in client");
}
@Override
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionDstu2Test.java
index 04eec27dd26..76159b8f661 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionDstu2Test.java
@@ -1,6 +1,7 @@
package ca.uhn.fhir.rest.server;
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
import javax.servlet.ServletException;
@@ -11,8 +12,13 @@ import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.StringDt;
+import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
+import ca.uhn.fhir.rest.annotation.ResourceParam;
+import ca.uhn.fhir.rest.annotation.Update;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.param.TokenParam;
public class ServerInvalidDefinitionDstu2Test {
@@ -33,6 +39,21 @@ public class ServerInvalidDefinitionDstu2Test {
}
}
+ @Test
+ public void testWrongConditionalUrlType() {
+ RestfulServer srv = new RestfulServer(ourCtx);
+ srv.setFhirContext(ourCtx);
+ srv.setResourceProviders(new UpdateWithWrongConditionalUrlType());
+
+ try {
+ srv.init();
+ fail();
+ } catch (ServletException e) {
+ assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException"));
+ assertThat(e.getCause().toString(), StringContains.containsString("Parameters annotated with @ConditionalUrlParam must be of type String, found incorrect parameteter in method \"public ca.uhn.fhir.rest.api.MethodOutcome ca.uhn.fhir.rest.server.ServerInvalidDefinitionDstu2Test$UpdateWithWrongConditionalUrlType.update(ca.uhn.fhir.rest.param.TokenParam,ca.uhn.fhir.model.dstu2.resource.Patient)"));
+ }
+ }
+
public static class OperationReturningOldBundleProvider implements IResourceProvider {
@Override
@@ -47,4 +68,18 @@ public class ServerInvalidDefinitionDstu2Test {
}
+ public static class UpdateWithWrongConditionalUrlType implements IResourceProvider {
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return Patient.class;
+ }
+
+ @Update
+ public MethodOutcome update(@ConditionalUrlParam TokenParam theToken, @ResourceParam Patient theParam2) {
+ return null;
+ }
+
+ }
+
}
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/DeleteConditionalDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/DeleteConditionalDstu3Test.java
new file mode 100644
index 00000000000..bad1a18c6dc
--- /dev/null
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/DeleteConditionalDstu3Test.java
@@ -0,0 +1,146 @@
+package ca.uhn.fhir.rest.server;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPut;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.servlet.ServletHandler;
+import org.eclipse.jetty.servlet.ServletHolder;
+import org.hl7.fhir.dstu3.model.IdType;
+import org.hl7.fhir.dstu3.model.Patient;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.model.api.IResource;
+import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.model.primitive.StringDt;
+import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
+import ca.uhn.fhir.rest.annotation.Delete;
+import ca.uhn.fhir.rest.annotation.IdParam;
+import ca.uhn.fhir.rest.annotation.OptionalParam;
+import ca.uhn.fhir.rest.annotation.ResourceParam;
+import ca.uhn.fhir.rest.annotation.Search;
+import ca.uhn.fhir.rest.annotation.Update;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.rest.client.IGenericClient;
+import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
+import ca.uhn.fhir.util.PortUtil;
+
+public class DeleteConditionalDstu3Test {
+ private static CloseableHttpClient ourClient;
+ private static String ourLastConditionalUrl;
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DeleteConditionalDstu3Test.class);
+ private static int ourPort;
+ private static FhirContext ourCtx = FhirContext.forDstu3();
+ private static Server ourServer;
+ private static IdType ourLastIdParam;
+ private static boolean ourLastRequestWasDelete;
+ private static IGenericClient ourHapiClient;
+
+
+
+ @Before
+ public void before() {
+ ourLastConditionalUrl = null;
+ ourLastIdParam = null;
+ ourLastRequestWasDelete = false;
+ }
+
+
+ @Test
+ public void testSearchStillWorks() throws Exception {
+
+ Patient patient = new Patient();
+ patient.addIdentifier().setValue("002");
+
+// HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_pretty=true");
+//
+// HttpResponse status = ourClient.execute(httpGet);
+//
+// String responseContent = IOUtils.toString(status.getEntity().getContent());
+// IOUtils.closeQuietly(status.getEntity().getContent());
+//
+// ourLog.info("Response was:\n{}", responseContent);
+
+ //@formatter:off
+ ourHapiClient
+ .delete()
+ .resourceConditionalByType(Patient.class)
+ .where(Patient.IDENTIFIER.exactly().systemAndIdentifier("SOMESYS","SOMEID"))
+ .execute();
+ //@formatter:on
+
+ assertTrue(ourLastRequestWasDelete);
+ assertEquals(null, ourLastIdParam);
+ assertEquals("Patient?identifier=SOMESYS%7CSOMEID", ourLastConditionalUrl);
+
+ }
+
+
+ @AfterClass
+ public static void afterClass() throws Exception {
+ ourServer.stop();
+ }
+
+
+ @BeforeClass
+ public static void beforeClass() throws Exception {
+ ourPort = PortUtil.findFreePort();
+ ourServer = new Server(ourPort);
+
+ PatientProvider patientProvider = new PatientProvider();
+
+ ServletHandler proxyHandler = new ServletHandler();
+ RestfulServer servlet = new RestfulServer(ourCtx);
+ servlet.setResourceProviders(patientProvider);
+ ServletHolder servletHolder = new ServletHolder(servlet);
+ proxyHandler.addServletWithMapping(servletHolder, "/*");
+ ourServer.setHandler(proxyHandler);
+ ourServer.start();
+
+ PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
+ HttpClientBuilder builder = HttpClientBuilder.create();
+ builder.setConnectionManager(connectionManager);
+ ourClient = builder.build();
+
+ ourCtx.getRestfulClientFactory().setSocketTimeout(500 * 1000);
+ ourHapiClient = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/");
+ ourHapiClient.registerInterceptor(new LoggingInterceptor());
+ }
+
+ public static class PatientProvider implements IResourceProvider {
+
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return Patient.class;
+ }
+
+ @Delete()
+ public MethodOutcome deletePatient(@IdParam IdType theIdParam, @ConditionalUrlParam String theConditional) {
+ ourLastRequestWasDelete = true;
+ ourLastConditionalUrl = theConditional;
+ ourLastIdParam = theIdParam;
+ return new MethodOutcome(new IdType("Patient/001/_history/002"));
+ }
+
+ }
+
+}