Some work on jamesagnew/hapi-fhir/#1297

This commit is contained in:
jelmer.terwal 2019-10-04 16:21:49 +02:00 committed by James Agnew
parent d0704269d7
commit 5002a087bb
8 changed files with 395 additions and 37 deletions

View File

@ -51,16 +51,8 @@ public class ReflectionUtil {
} }
public static Class<?> getGenericCollectionTypeOfField(Field next) { public static Class<?> getGenericCollectionTypeOfField(Field next) {
Class<?> type;
ParameterizedType collectionType = (ParameterizedType) next.getGenericType(); ParameterizedType collectionType = (ParameterizedType) next.getGenericType();
Type firstArg = collectionType.getActualTypeArguments()[0]; return getGenericCollectionTypeOf(collectionType.getActualTypeArguments()[0]);
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
ParameterizedType pt = ((ParameterizedType) firstArg);
type = (Class<?>) pt.getRawType();
} else {
type = (Class<?>) firstArg;
}
return type;
} }
/** /**
@ -84,42 +76,37 @@ public class ReflectionUtil {
} }
public static Class<?> getGenericCollectionTypeOfMethodParameter(Method theMethod, int theParamIndex) { public static Class<?> getGenericCollectionTypeOfMethodParameter(Method theMethod, int theParamIndex) {
Class<?> type;
Type genericParameterType = theMethod.getGenericParameterTypes()[theParamIndex]; Type genericParameterType = theMethod.getGenericParameterTypes()[theParamIndex];
if (Class.class.equals(genericParameterType) || Class.class.equals(genericParameterType.getClass())) { if (Class.class.equals(genericParameterType) || Class.class.equals(genericParameterType.getClass())) {
return null; return null;
} }
ParameterizedType collectionType = (ParameterizedType) genericParameterType; ParameterizedType collectionType = (ParameterizedType) genericParameterType;
Type firstArg = collectionType.getActualTypeArguments()[0]; return getGenericCollectionTypeOf(collectionType.getActualTypeArguments()[0]);
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) {
ParameterizedType pt = ((ParameterizedType) firstArg);
type = (Class<?>) pt.getRawType();
} else {
type = (Class<?>) firstArg;
}
return type;
} }
@SuppressWarnings({ "rawtypes" })
public static Class<?> getGenericCollectionTypeOfMethodReturnType(Method theMethod) { public static Class<?> getGenericCollectionTypeOfMethodReturnType(Method theMethod) {
Class<?> type;
Type genericReturnType = theMethod.getGenericReturnType(); Type genericReturnType = theMethod.getGenericReturnType();
if (!(genericReturnType instanceof ParameterizedType)) { if (!(genericReturnType instanceof ParameterizedType)) {
return null; return null;
} }
ParameterizedType collectionType = (ParameterizedType) genericReturnType; ParameterizedType collectionType = (ParameterizedType) genericReturnType;
Type firstArg = collectionType.getActualTypeArguments()[0]; return getGenericCollectionTypeOf(collectionType.getActualTypeArguments()[0]);
if (ParameterizedType.class.isAssignableFrom(firstArg.getClass())) { }
ParameterizedType pt = ((ParameterizedType) firstArg);
@SuppressWarnings({ "rawtypes" })
private static Class<?> getGenericCollectionTypeOf(Type theType) {
Class<?> type;
if (ParameterizedType.class.isAssignableFrom(theType.getClass())) {
ParameterizedType pt = ((ParameterizedType) theType);
type = (Class<?>) pt.getRawType(); type = (Class<?>) pt.getRawType();
} else if (firstArg instanceof TypeVariable<?>) { } else if (theType instanceof TypeVariable<?>) {
Type decl = ((TypeVariable) firstArg).getBounds()[0]; Type decl = ((TypeVariable) theType).getBounds()[0];
return (Class<?>) decl; return (Class<?>) decl;
} else if (firstArg instanceof WildcardType) { } else if (theType instanceof WildcardType) {
Type decl = ((WildcardType) firstArg).getUpperBounds()[0]; Type decl = ((WildcardType) theType).getUpperBounds()[0];
return (Class<?>) decl; return (Class<?>) decl;
} else { } else {
type = (Class<?>) firstArg; type = (Class<?>) theType;
} }
return type; return type;
} }
@ -154,8 +141,7 @@ public class ReflectionUtil {
public static Object newInstanceOfFhirServerType(String theType) { 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 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"; String wantedType = "ca.uhn.fhir.rest.api.server.IFhirVersionServer";
Object fhirServerVersion = newInstanceOfType(theType, errorMessage, wantedType); return newInstanceOfType(theType, errorMessage, wantedType);
return fhirServerVersion;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -89,6 +89,16 @@
<version>${project.version}</version> <version>${project.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies> </dependencies>
@ -118,7 +128,38 @@
<skip>true</skip> <skip>true</skip>
</configuration> </configuration>
</plugin> </plugin>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
</plugins> </plugins>
</build> </build>
<properties>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<kotlin.version>1.3.50</kotlin.version>
</properties>
</project> </project>

View File

@ -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
}
}

View File

@ -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<ExtendedOrganization>() {
override fun getResourceType(): Class<ExtendedOrganization>? = ExtendedOrganization::class.java
@Search
fun find(
@OptionalParam(name = "_id") theId: StringParam?,
@IncludeParam(allow = ["Patient:general-practitioner"]) includes: Collection<Include>?
): List<ExtendedOrganization> {
val organization = ExtendedOrganization().also {
it.id = "id"
}
return listOf(organization)
}
}
abstract class BaseResource<T: IAnyResource>: AbstractJaxRsResourceProvider<T>(FhirContext.forDstu3())

View File

@ -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)
}
}
}

176
hapi-kotlin-test/pom.xml Normal file
View File

@ -0,0 +1,176 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>hapi-fhir</artifactId>
<groupId>ca.uhn.hapi.fhir</groupId>
<version>4.1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hapi-kotlin-test</artifactId>
<name>HAPI FHIR - Kotlin tests</name>
<dependencies>
<!-- This dependency includes the core HAPI-FHIR classes -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
<version>${project.version}</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>ca.uhn.hapi.fhir</groupId>-->
<!-- <artifactId>hapi-fhir-validation-resources-dstu3</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>ca.uhn.hapi.fhir</groupId>-->
<!-- <artifactId>hapi-fhir-structures-dstu3</artifactId>-->
<!-- <version>${project.version}</version>-->
<!-- </dependency>-->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.dstu3</artifactId>
<version>${fhir_core_version}</version>
</dependency>
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0.1</version>
<scope>provided</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>javax.ejb</groupId>-->
<!-- <artifactId>ejb-api</artifactId>-->
<!-- <version>3.0</version>-->
<!-- <scope>provided</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty_version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty_version}</version>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<!-- This dependency includes the core HAPI-FHIR classes -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Include the HAPI server framework -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-server</artifactId>
<version>${project.version}</version>
</dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>${project.version}</version>
<classifier>classes</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
<configuration>
<compilerPlugins>
<plugin>no-arg</plugin>
<plugin>all-open</plugin>
</compilerPlugins>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<kotlin.version>1.3.50</kotlin.version>
</properties>
</project>

View File

@ -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<ExtendedPatient>() {
override fun getResourceType(): Class<ExtendedPatient>? = ExtendedPatient::class.java
}
abstract class BaseResource<T: IAnyResource>: AbstractJaxRsResourceProvider<T>()
fun main() {
}

View File

@ -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<CodeableConcept> = emptyList()
}