diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ReflectionUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ReflectionUtil.java index e22911d7507..e83b42d05db 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ReflectionUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ReflectionUtil.java @@ -51,16 +51,8 @@ public class ReflectionUtil { } public static Class getGenericCollectionTypeOfField(Field next) { - Class type; ParameterizedType collectionType = (ParameterizedType) next.getGenericType(); - Type firstArg = collectionType.getActualTypeArguments()[0]; - if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { - ParameterizedType pt = ((ParameterizedType) firstArg); - type = (Class) pt.getRawType(); - } else { - type = (Class) firstArg; - } - return type; + return getGenericCollectionTypeOf(collectionType.getActualTypeArguments()[0]); } /** @@ -84,42 +76,37 @@ public class ReflectionUtil { } public static Class getGenericCollectionTypeOfMethodParameter(Method theMethod, int theParamIndex) { - Class type; Type genericParameterType = theMethod.getGenericParameterTypes()[theParamIndex]; if (Class.class.equals(genericParameterType) || Class.class.equals(genericParameterType.getClass())) { return null; } ParameterizedType collectionType = (ParameterizedType) genericParameterType; - Type firstArg = collectionType.getActualTypeArguments()[0]; - if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { - ParameterizedType pt = ((ParameterizedType) firstArg); - type = (Class) pt.getRawType(); - } else { - type = (Class) firstArg; - } - return type; + return getGenericCollectionTypeOf(collectionType.getActualTypeArguments()[0]); } - @SuppressWarnings({ "rawtypes" }) public static Class getGenericCollectionTypeOfMethodReturnType(Method theMethod) { - Class type; Type genericReturnType = theMethod.getGenericReturnType(); if (!(genericReturnType instanceof ParameterizedType)) { return null; } ParameterizedType collectionType = (ParameterizedType) genericReturnType; - Type firstArg = collectionType.getActualTypeArguments()[0]; - if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { - ParameterizedType pt = ((ParameterizedType) firstArg); + return getGenericCollectionTypeOf(collectionType.getActualTypeArguments()[0]); + } + + @SuppressWarnings({ "rawtypes" }) + private static Class getGenericCollectionTypeOf(Type theType) { + Class type; + if (ParameterizedType.class.isAssignableFrom(theType.getClass())) { + ParameterizedType pt = ((ParameterizedType) theType); type = (Class) pt.getRawType(); - } else if (firstArg instanceof TypeVariable) { - Type decl = ((TypeVariable) firstArg).getBounds()[0]; + } else if (theType instanceof TypeVariable) { + Type decl = ((TypeVariable) theType).getBounds()[0]; return (Class) decl; - } else if (firstArg instanceof WildcardType) { - Type decl = ((WildcardType) firstArg).getUpperBounds()[0]; + } else if (theType instanceof WildcardType) { + Type decl = ((WildcardType) theType).getUpperBounds()[0]; return (Class) decl; } else { - type = (Class) firstArg; + type = (Class) theType; } return type; } @@ -154,8 +141,7 @@ public class ReflectionUtil { public static Object newInstanceOfFhirServerType(String theType) { String errorMessage = "Unable to instantiate server framework. Please make sure that hapi-fhir-server library is on your classpath!"; String wantedType = "ca.uhn.fhir.rest.api.server.IFhirVersionServer"; - Object fhirServerVersion = newInstanceOfType(theType, errorMessage, wantedType); - return fhirServerVersion; + return newInstanceOfType(theType, errorMessage, wantedType); } @SuppressWarnings("unchecked") diff --git a/hapi-fhir-jaxrsserver-example/pom.xml b/hapi-fhir-jaxrsserver-example/pom.xml index 63d7afa0de9..a91d125f5d5 100644 --- a/hapi-fhir-jaxrsserver-example/pom.xml +++ b/hapi-fhir-jaxrsserver-example/pom.xml @@ -1,7 +1,7 @@ 4.0.0 - ca.uhn.hapi.fhir @@ -83,12 +83,22 @@ ch.qos.logback logback-classic - - ca.uhn.hapi.fhir - hapi-fhir-test-utilities - ${project.version} - test - + + ca.uhn.hapi.fhir + hapi-fhir-test-utilities + ${project.version} + test + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-maven-noarg + ${kotlin.version} + @@ -118,7 +128,38 @@ true + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/main/java + + + + + test-compile + test-compile + + + ${project.basedir}/src/test/kotlin + ${project.basedir}/src/test/java + + + + + + + true + 1.3.50 + diff --git a/hapi-fhir-jaxrsserver-example/src/main/kotlin/cn/uhn/fhir/jaxrs/server/example/ExtendedOrganization.kt b/hapi-fhir-jaxrsserver-example/src/main/kotlin/cn/uhn/fhir/jaxrs/server/example/ExtendedOrganization.kt new file mode 100644 index 00000000000..05d61056891 --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/main/kotlin/cn/uhn/fhir/jaxrs/server/example/ExtendedOrganization.kt @@ -0,0 +1,14 @@ +package cn.uhn.fhir.jaxrs.server.example + +import ca.uhn.fhir.model.api.annotation.ResourceDef +import org.hl7.fhir.dstu3.model.BaseResource +import org.hl7.fhir.dstu3.model.Organization +import org.hl7.fhir.instance.model.api.IIdType + +@ResourceDef(name = "Organization") +open class ExtendedOrganization : Organization() { + + override fun setId(value: IIdType?): BaseResource? { + return this + } +} diff --git a/hapi-fhir-jaxrsserver-example/src/main/kotlin/cn/uhn/fhir/jaxrs/server/example/ExtendedOrganizationResource.kt b/hapi-fhir-jaxrsserver-example/src/main/kotlin/cn/uhn/fhir/jaxrs/server/example/ExtendedOrganizationResource.kt new file mode 100644 index 00000000000..54ff9db16ba --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/main/kotlin/cn/uhn/fhir/jaxrs/server/example/ExtendedOrganizationResource.kt @@ -0,0 +1,35 @@ +package cn.uhn.fhir.jaxrs.server.example + +import ca.uhn.fhir.context.FhirContext +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider +import ca.uhn.fhir.model.api.Include +import ca.uhn.fhir.rest.annotation.IncludeParam +import ca.uhn.fhir.rest.annotation.OptionalParam +import ca.uhn.fhir.rest.annotation.Search +import ca.uhn.fhir.rest.api.Constants +import ca.uhn.fhir.rest.param.StringParam +import org.hl7.fhir.instance.model.api.IAnyResource +import javax.ejb.Stateless +import javax.ws.rs.Path +import javax.ws.rs.Produces +import javax.ws.rs.core.MediaType + +@Path("Organization") +@Stateless +@Produces(MediaType.APPLICATION_JSON, Constants.CT_FHIR_JSON, Constants.CT_FHIR_XML) +class ExtendedOrganizationResource : BaseResource() { + override fun getResourceType(): Class? = ExtendedOrganization::class.java + + @Search + fun find( + @OptionalParam(name = "_id") theId: StringParam?, + @IncludeParam(allow = ["Patient:general-practitioner"]) includes: Collection? + ): List { + val organization = ExtendedOrganization().also { + it.id = "id" + } + return listOf(organization) + } +} + +abstract class BaseResource: AbstractJaxRsResourceProvider(FhirContext.forDstu3()) diff --git a/hapi-fhir-jaxrsserver-example/src/test/kotlin/ca/uhn/fhir/jaxrs/server/example/ExtendedOrganizationResourceTest.kt b/hapi-fhir-jaxrsserver-example/src/test/kotlin/ca/uhn/fhir/jaxrs/server/example/ExtendedOrganizationResourceTest.kt new file mode 100644 index 00000000000..edff3030942 --- /dev/null +++ b/hapi-fhir-jaxrsserver-example/src/test/kotlin/ca/uhn/fhir/jaxrs/server/example/ExtendedOrganizationResourceTest.kt @@ -0,0 +1,69 @@ +package ca.uhn.fhir.jaxrs.server.example + +import ca.uhn.fhir.test.utilities.JettyUtil +import ca.uhn.fhir.util.TestUtil +import cn.uhn.fhir.jaxrs.server.example.ExtendedOrganizationResource +import org.apache.commons.lang3.StringUtils +import org.eclipse.jetty.server.Server +import org.eclipse.jetty.servlet.ServletContextHandler +import org.hamcrest.CoreMatchers.`is` +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder +import org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher +import org.junit.AfterClass +import org.junit.Assert.assertThat +import org.junit.BeforeClass +import org.junit.Test +import javax.ws.rs.core.Response + +class ExtendedOrganizationResourceTest { + + @Test + fun makeSureSearchDoesNotThrowOnIncludeParam() { + val response = ResteasyClientBuilder() + .build() + .target("http://localhost:$ourPort/Organization?_id=1") + .request() + .method("GET") + assertThat( + "This should not explode!", + response.status, + `is`(Response.Status.OK.statusCode) + ) + } + + companion object { + private var ourPort: Int = 0 + private lateinit var jettyServer: Server + + @JvmStatic + @AfterClass + @Throws(Exception::class) + fun afterClassClearContext() { + JettyUtil.closeServer(jettyServer) + TestUtil.clearAllStaticFieldsForUnitTest() + } + + @JvmStatic + @BeforeClass + @Throws(Exception::class) + fun setUpClass() { + val context = ServletContextHandler(ServletContextHandler.SESSIONS).also { + it.contextPath = "/" + } + jettyServer = Server(0).also { + it.handler = context + } + val jerseyServlet = context.addServlet(HttpServletDispatcher::class.java, "/*").also { + it.initOrder = 0 + //@formatter:off + it.setInitParameter( + "resteasy.resources", + StringUtils.join(listOf(ExtendedOrganizationResource::class.java.canonicalName), ",") + ) + //@formatter:on + } + JettyUtil.startServer(jettyServer) + ourPort = JettyUtil.getPortForStartedServer(jettyServer) + } + } +} diff --git a/hapi-kotlin-test/pom.xml b/hapi-kotlin-test/pom.xml new file mode 100644 index 00000000000..2ecc4d98617 --- /dev/null +++ b/hapi-kotlin-test/pom.xml @@ -0,0 +1,176 @@ + + + + hapi-fhir + ca.uhn.hapi.fhir + 4.1.0-SNAPSHOT + + 4.0.0 + + hapi-kotlin-test + + HAPI FHIR - Kotlin tests + + + + + ca.uhn.hapi.fhir + hapi-fhir-jaxrsserver-base + ${project.version} + + + + + + + + + + + + + ca.uhn.hapi.fhir + org.hl7.fhir.dstu3 + ${fhir_core_version} + + + javax.ws.rs + javax.ws.rs-api + 2.0.1 + provided + + + + + + + + + + org.eclipse.jetty + jetty-server + ${jetty_version} + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + + + org.jboss.resteasy + resteasy-jaxrs + + + org.jboss.resteasy + resteasy-client + + + ch.qos.logback + logback-classic + + + ca.uhn.hapi.fhir + hapi-fhir-test-utilities + ${project.version} + test + + + + + ca.uhn.hapi.fhir + hapi-fhir-base + ${project.version} + + + + + ca.uhn.hapi.fhir + hapi-fhir-server + ${project.version} + + + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + ${project.version} + war + provided + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + ${project.version} + classes + provided + + + + org.jetbrains.kotlin + kotlin-maven-allopen + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-maven-noarg + ${kotlin.version} + + + + + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + + ${project.basedir}/src/main/kotlin + ${project.basedir}/src/main/java + + + + + test-compile + test-compile + + + ${project.basedir}/src/test/kotlin + ${project.basedir}/src/test/java + + + + + + + no-arg + all-open + + + + + org.apache.felix + maven-bundle-plugin + true + + + + ca.uhn.hapi.fhir.hapi-fhir-base + + + + + + + + + true + 1.3.50 + + diff --git a/hapi-kotlin-test/src/main/kotlin/ca/uhn/fhir/rest/server/Server.kt b/hapi-kotlin-test/src/main/kotlin/ca/uhn/fhir/rest/server/Server.kt new file mode 100644 index 00000000000..ab030221cf7 --- /dev/null +++ b/hapi-kotlin-test/src/main/kotlin/ca/uhn/fhir/rest/server/Server.kt @@ -0,0 +1,15 @@ +package ca.uhn.fhir.rest.server + +import ca.uhn.fhir.rest.server.resources.ExtendedPatient +import ca.uhn.fhir.jaxrs.server.AbstractJaxRsResourceProvider +import org.hl7.fhir.instance.model.api.IAnyResource + +class Server : BaseResource() { + override fun getResourceType(): Class? = ExtendedPatient::class.java +} + +abstract class BaseResource: AbstractJaxRsResourceProvider() + +fun main() { + +} diff --git a/hapi-kotlin-test/src/main/kotlin/ca/uhn/fhir/rest/server/resources/ExtendedPatient.kt b/hapi-kotlin-test/src/main/kotlin/ca/uhn/fhir/rest/server/resources/ExtendedPatient.kt new file mode 100644 index 00000000000..70ab2e347b8 --- /dev/null +++ b/hapi-kotlin-test/src/main/kotlin/ca/uhn/fhir/rest/server/resources/ExtendedPatient.kt @@ -0,0 +1,22 @@ +package ca.uhn.fhir.rest.server.resources + +import ca.uhn.fhir.model.api.annotation.Child +import ca.uhn.fhir.model.api.annotation.Extension +import ca.uhn.fhir.model.api.annotation.ResourceDef +import org.hl7.fhir.dstu3.model.CodeableConcept +import org.hl7.fhir.dstu3.model.Patient +import org.hl7.fhir.instance.model.api.IBaseResource + +import java.util.Collections.emptyList + +@ResourceDef(name = "Patient") +class ExtendedPatient : Patient() { + + @Child(name = "status") + @Extension( + url = "http://some.url", + definedLocally = false, + isModifier = false + ) + var status: List = emptyList() +}