From d826884d02eb9c5066b1f91b64ac2cab341e6121 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 28 Jun 2017 17:11:44 +0100 Subject: [PATCH] Ensure @Component scanned from jar on classpath can be inspected And test it using a new POF sample. --- ...ntextFunctionCatalogAutoConfiguration.java | 16 +-- ...FunctionCatalogAutoConfigurationTests.java | 38 ++++++ .../src/test/resources/greeter.jar | Bin 0 -> 1015 bytes spring-cloud-function-samples/pom.xml | 1 + .../spring-cloud-function-sample-pof/pom.xml | 113 ++++++++++++++++++ .../src/main/java/functions/Application.java | 30 +++++ .../src/main/java/functions/Greeter.java | 26 ++++ 7 files changed, 216 insertions(+), 8 deletions(-) create mode 100644 spring-cloud-function-context/src/test/resources/greeter.jar create mode 100644 spring-cloud-function-samples/spring-cloud-function-sample-pof/pom.xml create mode 100644 spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Application.java create mode 100644 spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Greeter.java diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java index e1870b7e4..ba2e9be9e 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfiguration.java @@ -59,7 +59,7 @@ import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; import org.springframework.core.type.StandardMethodMetadata; import org.springframework.core.type.classreading.MethodMetadataReadingVisitor; import org.springframework.messaging.Message; @@ -407,7 +407,13 @@ public class ContextFunctionCatalogAutoConfiguration { .getIntrospectedMethod().getGenericReturnType(); param = extractType(type, paramType, index); } - else if (source instanceof FileSystemResource) { + else if (source instanceof MethodMetadataReadingVisitor) { + // A component scan with @Beans + MethodMetadataReadingVisitor visitor = (MethodMetadataReadingVisitor) source; + Type type = findBeanType(definition, visitor); + param = extractType(type, paramType, index); + } + else if (source instanceof Resource) { try { Class beanType = ClassUtils.forName(definition.getBeanClassName(), null); @@ -427,12 +433,6 @@ public class ContextFunctionCatalogAutoConfiguration { "Cannot instrospect bean: " + definition, e); } } - else if (source instanceof MethodMetadataReadingVisitor) { - // A component scan with @Beans - MethodMetadataReadingVisitor visitor = (MethodMetadataReadingVisitor) source; - Type type = findBeanType(definition, visitor); - param = extractType(type, paramType, index); - } else { ResolvableType resolvable = (ResolvableType) getField(definition, "targetType"); diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfigurationTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfigurationTests.java index d8f623edc..21b6ba29f 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfigurationTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/ContextFunctionCatalogAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.cloud.function.context; +import java.net.URL; +import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -39,9 +41,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.messaging.Message; import org.springframework.messaging.support.MessageBuilder; +import org.springframework.util.ClassUtils; +import org.springframework.util.ReflectionUtils; import org.springframework.util.StreamUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -139,6 +144,33 @@ public class ContextFunctionCatalogAutoConfigurationTests { assertThat(inspector.getInputWrapper("function")).isAssignableFrom(Map.class); } + @Test + public void componentScanJarFunction() { + try { + create("greeter.jar", ComponentScanJarConfiguration.class); + assertThat(context.getBean("greeter")).isInstanceOf(Function.class); + assertThat(catalog.lookupFunction("greeter")).isInstanceOf(Function.class); + assertThat(inspector.getInputType("greeter")).isAssignableFrom(String.class); + assertThat(inspector.getInputWrapper("greeter")) + .isAssignableFrom(String.class); + } + finally { + ClassUtils.overrideThreadContextClassLoader(getClass().getClassLoader()); + } + } + + private void create(String jarfile, Class config, String... props) { + try { + URL[] urls = new URL[] { new ClassPathResource(jarfile).getURL() }; + ClassUtils.overrideThreadContextClassLoader( + new URLClassLoader(urls, getClass().getClassLoader())); + create(config, props); + } + catch (Exception e) { + ReflectionUtils.rethrowRuntimeException(e); + } + } + @Test public void simpleSupplier() { create(SimpleConfiguration.class); @@ -304,6 +336,12 @@ public class ContextFunctionCatalogAutoConfigurationTests { protected static class ComponentScanConfiguration { } + @EnableAutoConfiguration + @Configuration + @FunctionScan + protected static class ComponentScanJarConfiguration { + } + @EnableAutoConfiguration @Configuration protected static class GenericFluxConfiguration { diff --git a/spring-cloud-function-context/src/test/resources/greeter.jar b/spring-cloud-function-context/src/test/resources/greeter.jar new file mode 100644 index 0000000000000000000000000000000000000000..24671c2bacc48e6583eeb0bdc95abe63bf34674e GIT binary patch literal 1015 zcmWIWW@Zs#;Nak3$mzS|#ef7j8CV#6T|*poJ^kGD|D9rBU}gyLX6FE@V1g7v*#$H@w>oU54?MO7XMY;6}=B4>WmEH>rZi8b0E*FO+i61J-9UH>YpzU@K6 z%0~`sUmtQU{*5>1bgsn}>HSN3)&+0Da549=(c<89N_E2*!z&%=3=dVoeCmV5+%NCz7*`9y8MQ3_vXT-(f@pB)V!H{ zYTrzQjUo$gg*xl{2yMPx7&pPNGcfVP`sWW0s9FC!RGBtCyW*}!=kHGrOVc0R?!3Pw zNZu}uqx;mJSEo_eg^YVeu@TSPpEQ1GkdJMg$o~Atgm6Y>!)dq77i9a%oGH@j zKgoK<;@3=u;uXe0RvYft9LZ|m_>uYCb7_%RM+LoR|LG0bH|tZC&9|y4FV}|8(lv13 z`u)wWjM)28*R!fWi{BB{x*Ya@d+63MK5>u7Leq}#_#_TWsnULr4dFZ z5eC$R4ok(LgpLZ}DHoLN(X}EcJy0@709zmvt`#ZKgG}IJz@0=9CL9JbkrOP!(V!%Y g>>*H+MS#~pCPE)d0uJzIWdkW>0m5HE`Z?I!09q1G@c;k- literal 0 HcmV?d00001 diff --git a/spring-cloud-function-samples/pom.xml b/spring-cloud-function-samples/pom.xml index e843e2cb7..6f545509f 100644 --- a/spring-cloud-function-samples/pom.xml +++ b/spring-cloud-function-samples/pom.xml @@ -14,6 +14,7 @@ spring-cloud-function-sample + spring-cloud-function-sample-pof spring-cloud-function-sample-pojo spring-cloud-function-sample-compiler spring-cloud-function-sample-task diff --git a/spring-cloud-function-samples/spring-cloud-function-sample-pof/pom.xml b/spring-cloud-function-samples/spring-cloud-function-sample-pof/pom.xml new file mode 100644 index 000000000..6ae448ccc --- /dev/null +++ b/spring-cloud-function-samples/spring-cloud-function-sample-pof/pom.xml @@ -0,0 +1,113 @@ + + 4.0.0 + + com.example + pof-sample + 1.0.0.BUILD-SNAPSHOT + jar + spring-cloud-function-sample-pof + Spring Cloud Function Web Support + + + org.springframework.boot + spring-boot-starter-parent + 1.5.2.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + 3.0.7.RELEASE + 1.0.0.BUILD-SNAPSHOT + + + + + org.springframework.cloud + spring-cloud-function-web + ${spring-cloud-function.version} + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + exec + + + + org.springframework.boot.experimental + spring-boot-thin-layout + 1.0.4.RELEASE + + + + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot-local + + true + + + false + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone-local + + false + + + + spring-releases + Spring Releases + https://repo.spring.io/release + + false + + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/libs-snapshot-local + + true + + + false + + + + spring-milestones + Spring Milestones + https://repo.spring.io/libs-milestone-local + + false + + + + spring-releases + Spring Releases + https://repo.spring.io/libs-release-local + + false + + + + + diff --git a/spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Application.java b/spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Application.java new file mode 100644 index 000000000..c3afa0057 --- /dev/null +++ b/spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Application.java @@ -0,0 +1,30 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.function.context.FunctionScan; + +@FunctionScan +@SpringBootApplication +public class Application { + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } +} diff --git a/spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Greeter.java b/spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Greeter.java new file mode 100644 index 000000000..0ae801c82 --- /dev/null +++ b/spring-cloud-function-samples/spring-cloud-function-sample-pof/src/main/java/functions/Greeter.java @@ -0,0 +1,26 @@ +/* + * Copyright 2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package functions; + +import java.util.function.Function; + +public class Greeter implements Function { + + public String apply(String name) { + return "Hello " + name; + } +}