Merge remote-tracking branch 'remotes/origin/master' into ks-better-inmemory-error

This commit is contained in:
Ken Stevens 2019-10-22 17:10:06 -04:00
commit dbcff8d1fa
11 changed files with 402 additions and 44 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

@ -50,14 +50,12 @@ public interface IAnyResource extends IBaseResource {
String getId();
@Override
IIdType getIdElement();
IPrimitiveType<String> getLanguageElement();
Object getUserData(String name);
@Override
IAnyResource setId(String theId);
void setUserData(String name, Object value);

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,12 @@
<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>
</dependencies>
@ -120,5 +120,4 @@
</plugin>
</plugins>
</build>
</project>

13
pom.xml
View File

@ -68,7 +68,7 @@
<dependencies>
<!-- Cobertura is here as a 'provided' depdendency just to get the @CoverageIgnore annotation. It would be nice if there was a better way for this.. -->
<!-- <dependency> <groupId>net.sourceforge.cobertura</groupId> <artifactId>cobertura</artifactId> <version>2.1.1</version> <scope>provided</scope> <exclusions> <exclusion> <artifactId>jetty</artifactId>
<!-- <dependency> <groupId>net.sourceforge.cobertura</groupId> <artifactId>cobertura</artifactId> <version>2.1.1</version> <scope>provided</scope> <exclusions> <exclusion> <artifactId>jetty</artifactId>
<groupId>org.mortbay.jetty</groupId> </exclusion> </exclusions> </dependency> -->
<dependency>
<groupId>junit</groupId>
@ -563,6 +563,10 @@
<id>tuomoa</id>
<name>Tuomo Ala-Vannesluoma</name>
</developer>
<developer>
<id>jelmerterwal</id>
<name>Jelmer ter Wal</name>
</developer>
</developers>
<licenses>
@ -1819,7 +1823,7 @@
<ignore></ignore>
</action>
</pluginExecution>
<!--
<!--
<pluginExecution>
<pluginExecutionFilter>
<groupId>
@ -2335,7 +2339,7 @@
</modules>
<build>
<plugins>
<!-- <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>${maven_assembly_plugin_version}</version> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals>
<!-- <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>${maven_assembly_plugin_version}</version> <executions> <execution> <phase>package</phase> <goals> <goal>single</goal> </goals>
<configuration> <attach>false</attach> <descriptors> <descriptor>${project.basedir}/src/assembly/hapi-fhir-sample-projects.xml</descriptor> </descriptors> </configuration> </execution> </executions> </plugin> -->
</plugins>
</build>
@ -2360,7 +2364,7 @@
<goal>sign</goal>
</goals>
<configuration>
<!--
<!--
These arguments are needed for GPG 2.1+ per
https://stackoverflow.com/questions/53992950/maven-gpg-plugin-failing-with-inappropriate-ioctl-for-device-when-running-unde
-->
@ -2468,6 +2472,7 @@
<module>example-projects/hapi-fhir-jpaserver-dynamic</module>
<module>example-projects/hapi-fhir-jpaserver-example-postgres</module>
-->
<module>tests/hapi-fhir-base-test-jaxrsserver-kotlin</module>
<module>tests/hapi-fhir-base-test-mindeps-client</module>
<module>tests/hapi-fhir-base-test-mindeps-server</module>
<module>hapi-fhir-spring-boot</module>

View File

@ -439,6 +439,10 @@
<![CDATA[<code>ProcedureRequest?someCustomParameter.BAD_NAME=</code>]]>, the server would ignore this
parameter instead of incorrectly returning an error. This has been corrected.
</action>
<action type="fix" issue="1526">
Several issues with HAPI FHIR's annotation scanner that prevented use with Kotlin based
resource providers have been corrected. Thanks to Jelmer ter Wal for the pull request!
</action>
</release>
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
<action type="fix">

View File

@ -0,0 +1,165 @@
<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
if you are using this file as a basis for your own project. -->
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>4.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-base-test-jaxrsserver-kotlin</artifactId>
<packaging>war</packaging>
<name>HAPI FHIR JAX-RS Server Kotlin test</name>
<repositories>
<repository>
<id>oss-snapshots</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<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-structures-dstu2</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>hapi-fhir-structures-r4</artifactId>
<version>${project.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>
<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>
<finalName>hapi-fhir-jaxrsserver-example</finalName>
<!-- This is to run the integration tests -->
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<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,18 @@
package cn.uhn.fhir.jaxrs.server.example
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.Organization
@ResourceDef(name = "Organization")
class ExtendedOrganization : Organization() {
@Child(name = "someEnumerationInAList")
@Extension(
url = "http://test.url",
definedLocally = false,
isModifier = false
)
var legalStatus: List<CodeableConcept> = emptyList()
}

View File

@ -0,0 +1,32 @@
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 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 : AbstractJaxRsResourceProvider<ExtendedOrganization>(FhirContext.forDstu3()) {
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)
}
}

View File

@ -0,0 +1,52 @@
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
<!--
<filter>
<filter-name>CORS Filter</filter-name>
<filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>
<init-param>
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
</init-param>
<init-param>
<description>A comma separated list of allowed headers when making a non simple CORS request.</description>
<param-name>cors.allowed.headers</param-name>
<param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
<param-name>cors.exposed.headers</param-name>
<param-value>Location,Content-Location</param-value>
</init-param>
<init-param>
<description>A flag that suggests if CORS is supported with cookies</description>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<description>A flag to control logging</description>
<param-name>cors.logging.enabled</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
<param-name>cors.preflight.maxage</param-name>
<param-value>300</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-->
</web-app>

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

View File

@ -0,0 +1,30 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n
</pattern>
</encoder>
</appender>
<logger name="org.eclipse" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.apache" additivity="false" level="info">
<appender-ref ref="STDOUT" />
</logger>
<logger name="org.thymeleaf" additivity="false" level="warn">
<appender-ref ref="STDOUT" />
</logger>
<!--
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="trace">
<appender-ref ref="STDOUT" />
</logger>
-->
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>