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) {
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")

View File

@ -1,7 +1,7 @@
<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">
<modelVersion>4.0.0</modelVersion>
<!-- Note: HAPI projects use the "hapi-fhir" POM as their base to provide easy management. You do not need to use this in your own projects, so the "parent" tag and it's contents below may be removed
<!-- Note: HAPI projects use the "hapi-fhir" POM as their base to provide easy management. You do not need to use this in your own projects, so the "parent" tag and it's contents below may be removed
if you are using this file as a basis for your own project. -->
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
@ -83,12 +83,22 @@
<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>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>${project.version}</version>
<scope>test</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>
@ -118,7 +128,38 @@
<skip>true</skip>
</configuration>
</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>
</build>
<properties>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
<kotlin.version>1.3.50</kotlin.version>
</properties>
</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()
}