From e4b08a083c9558e0d4f4315699bf3bfc6cd6822b Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Fri, 1 Feb 2019 15:48:32 +0100 Subject: [PATCH] Turned on checkstyle --- .editorconfig | 14 + .mvn/settings.xml | 24 +- .springformat | 0 docs/pom.xml | 31 +- pipeline.yml | 114 +-- pom.xml | 31 +- spring-cloud-function-adapters/pom.xml | 7 +- .../spring-cloud-function-adapter-aws/pom.xml | 5 +- .../SpringBootApiGatewayRequestHandler.java | 17 +- .../aws/SpringBootKinesisEventHandler.java | 25 +- .../adapter/aws/SpringBootRequestHandler.java | 8 +- .../adapter/aws/SpringBootStreamHandler.java | 18 +- .../aws/SpringFunctionInitializer.java | 137 ++-- ...ringBootApiGatewayRequestHandlerTests.java | 77 +- .../SpringBootKinesisEventHandlerTests.java | 264 +++--- .../aws/SpringBootRequestHandlerTests.java | 19 +- .../aws/SpringBootStreamHandlerTests.java | 33 +- .../aws/SpringFunctionInitializerTests.java | 59 +- .../pom.xml | 9 +- .../azure/AzureSpringBootRequestHandler.java | 9 +- .../azure/AzureSpringFunctionInitializer.java | 126 +-- .../AzureSpringBootRequestHandlerTests.java | 37 +- .../AzureSpringFunctionInitializerTests.java | 16 +- .../adapter/azure/TestExecutionContext.java | 8 +- .../pom.xml | 5 +- .../adapter/openwhisk/FunctionProperties.java | 7 +- .../openwhisk/OpenWhiskActionApplication.java | 5 +- .../openwhisk/OpenWhiskActionHandler.java | 20 +- .../openwhisk/OpenWhiskActionRequest.java | 15 +- .../OpenWhiskFunctionInitializer.java | 12 +- .../openwhisk/OpenWhiskInitRequest.java | 9 +- .../openwhisk/OpenWhiskActionHandlerTest.java | 21 +- .../resources/application-test.properties | 4 +- spring-cloud-function-compiler/pom.xml | 4 +- .../compiler/AbstractFunctionCompiler.java | 52 +- .../compiler/CompilationResultFactory.java | 3 +- .../compiler/CompiledFunctionFactory.java | 20 +- .../function/compiler/ConsumerCompiler.java | 13 +- .../function/compiler/FunctionCompiler.java | 16 +- .../function/compiler/SupplierCompiler.java | 13 +- .../app/CompiledFunctionRegistry.java | 22 +- .../compiler/app/CompilerApplication.java | 5 +- .../compiler/app/CompilerController.java | 11 +- .../FunctionProxyApplicationListener.java | 16 +- ...eableFilterableJavaFileObjectIterable.java | 82 +- .../java/CompilationFailedException.java | 5 +- .../compiler/java/CompilationMessage.java | 69 +- .../java/CompilationOutputCollector.java | 49 +- .../compiler/java/CompilationResult.java | 59 +- .../java/CompiledClassDefinition.java | 17 +- .../compiler/java/CompositeProxySelector.java | 2 +- .../compiler/java/DependencyResolver.java | 56 +- .../compiler/java/DirEntryJavaFileObject.java | 45 +- .../compiler/java/DirEnumeration.java | 49 +- .../compiler/java/InMemoryJavaFileObject.java | 143 ++-- .../compiler/java/IterableClasspath.java | 334 ++++---- .../compiler/java/IterableJrtModule.java | 119 +-- .../compiler/java/JrtEntryJavaFileObject.java | 54 +- .../compiler/java/JrtFsEnumeration.java | 100 ++- .../function/compiler/java/MavenSettings.java | 2 +- .../compiler/java/MavenSettingsReader.java | 24 +- .../java/MemoryBasedJavaFileManager.java | 774 ++++++++++-------- .../java/NestedZipEntryJavaFileObject.java | 95 ++- .../compiler/java/RuntimeJavaCompiler.java | 71 +- .../compiler/java/SimpleClassLoader.java | 21 +- .../compiler/java/ZipEntryJavaFileObject.java | 57 +- .../proxy/AbstractByteCodeLoadingProxy.java | 14 +- .../proxy/AbstractLambdaCompilingProxy.java | 18 +- .../proxy/ByteCodeLoadingConsumer.java | 11 +- .../proxy/ByteCodeLoadingFunction.java | 14 +- .../proxy/ByteCodeLoadingSupplier.java | 11 +- .../proxy/LambdaCompilingConsumer.java | 9 +- .../proxy/LambdaCompilingFunction.java | 11 +- .../proxy/LambdaCompilingSupplier.java | 9 +- .../CompilerDependencyResolutionTests.java | 364 ++++---- .../compiler/ConsumerCompilerTests.java | 8 +- .../compiler/FunctionCompilerTests.java | 14 +- .../compiler/SupplierCompilerTests.java | 19 +- .../java/RuntimeJavaCompilerTests.java | 152 ++-- .../proxy/ByteCodeLoadingFunctionTests.java | 49 +- .../function/core/FunctionFactoryUtils.java | 7 +- .../core/FunctionFactoryUtilsTests.java | 29 +- spring-cloud-function-context/pom.xml | 13 +- .../context/AbstractFunctionRegistry.java | 12 +- .../function/context/FunctionCatalog.java | 23 +- .../context/FunctionRegistration.java | 32 +- .../function/context/FunctionRegistry.java | 2 +- .../cloud/function/context/FunctionType.java | 240 +++--- .../context/FunctionalSpringApplication.java | 47 +- .../function/context/WrapperDetector.java | 2 +- .../context/catalog/FunctionCatalogEvent.java | 3 +- .../context/catalog/FunctionInspector.java | 2 +- .../catalog/FunctionRegistrationEvent.java | 8 +- .../catalog/FunctionUnregistrationEvent.java | 8 +- .../catalog/InMemoryFunctionCatalog.java | 34 +- ...ntextFunctionCatalogAutoConfiguration.java | 177 ++-- .../ContextFunctionCatalogInitializer.java | 69 +- .../context/config/FluxWrapperDetector.java | 2 +- .../context/config/FunctionContextUtils.java | 187 ++--- .../context/message/MessageUtils.java | 4 +- .../test/FunctionalSpringBootTest.java | 10 +- .../test/FunctionalTestContextLoader.java | 3 +- .../cloud/function/json/GsonMapper.java | 8 +- .../cloud/function/json/JacksonMapper.java | 9 +- .../cloud/function/json/JsonMapper.java | 15 +- .../spring-configuration-metadata.json | 34 +- .../main/resources/META-INF/spring.factories | 4 +- .../context/FunctionRegistrationTests.java | 4 +- .../function/context/FunctionTypeTests.java | 38 +- .../catalog/InMemoryFunctionCatalogTests.java | 31 +- .../BeanFactoryFunctionCatalogTests.java | 144 ++-- ...FunctionCatalogAutoConfigurationTests.java | 492 ++++++----- ...ontextFunctionCatalogInitializerTests.java | 123 +-- .../ContextFunctionPostProcessorTests.java | 115 +-- .../string/FunctionalStringSourceTests.java | 14 +- .../context/test/FunctionalTests.java | 12 +- .../function/inject/FooConfiguration.java | 6 +- .../cloud/function/scan/ScannedFunction.java | 4 +- .../cloud/function/test/GenericFunction.java | 5 +- .../cloud/function/util/JsonMapperTests.java | 31 +- spring-cloud-function-core/pom.xml | 4 +- .../cloud/function/core/FluxConsumer.java | 8 +- .../cloud/function/core/FluxFunction.java | 11 +- .../cloud/function/core/FluxSupplier.java | 24 +- .../function/core/FluxToMonoFunction.java | 17 +- .../cloud/function/core/FluxWrapper.java | 6 +- .../core/FunctionFactoryMetadata.java | 7 +- .../cloud/function/core/Isolated.java | 3 +- .../cloud/function/core/IsolatedConsumer.java | 7 +- .../cloud/function/core/IsolatedFunction.java | 6 +- .../cloud/function/core/IsolatedSupplier.java | 7 +- .../function/core/MonoToFluxFunction.java | 18 +- spring-cloud-function-dependencies/pom.xml | 4 +- spring-cloud-function-deployer/pom.xml | 12 +- .../src/it/flux/pom.xml | 10 +- .../com/example/functions/FunctionApp.java | 17 +- .../src/it/support/pom.xml | 10 +- .../com/example/functions/DoubleLogger.java | 3 +- .../java/com/example/functions/Emitter.java | 5 +- .../com/example/functions/FunctionApp.java | 11 +- .../com/example/functions/LengthCounter.java | 3 +- .../deployer/ApplicationBootstrap.java | 25 +- .../function/deployer/ApplicationRunner.java | 13 +- .../function/deployer/ContextRunner.java | 43 +- .../deployer/EnableFunctionDeployer.java | 6 +- .../deployer/FunctionApplication.java | 4 +- .../FunctionCreatorConfiguration.java | 212 ++--- .../FunctionDeployerConfiguration.java | 3 +- .../function/deployer/FunctionProperties.java | 63 +- .../deployer/SingleEntryFunctionRegistry.java | 10 +- .../function/deployer/AdhocTestSuite.java | 2 +- .../deployer/ApplicationRunnerTests.java | 3 +- .../function/deployer/ContextRunnerTests.java | 3 +- .../FunctionCreatorConfigurationTests.java | 44 +- .../SingleEntryFunctionRegistryTests.java | 26 +- .../SpringFunctionAppConfigurationTests.java | 22 +- ...FunctionAppExplodedConfigurationTests.java | 28 +- .../SpringFunctionFluxConfigurationTests.java | 35 +- .../cloud/function/test/Doubler.java | 4 +- .../cloud/function/test/Frenchizer.java | 11 +- .../cloud/function/test/FunctionApp.java | 9 +- .../function/test/FunctionInitializer.java | 15 +- .../function/test/FunctionRegistrar.java | 15 +- .../cloud/function/test/NumberEmitter.java | 4 +- .../cloud/function/test/Printer.java | 3 +- .../cloud/function/test/SpringDoubler.java | 10 +- spring-cloud-function-kotlin/pom.xml | 6 +- ...tlinLambdaToFunctionAutoConfiguration.java | 83 +- ...onCatalogAutoConfigurationKotlinTests.java | 69 +- .../kotlin/KotlinLambdasConfiguration.kt | 28 +- .../function-sample-aws/build.gradle | 43 +- .../function-sample-aws/pom.xml | 10 +- .../src/main/java/example/Config.java | 35 +- .../src/main/java/example/Handler.java | 2 +- .../src/main/java/example/Properties.java | 11 +- .../src/main/resources/log4j.properties | 5 +- .../src/test/java/example/MapTests.java | 5 +- .../function-sample-azure/pom.xml | 26 +- .../src/main/azure/local.settings.json | 12 +- .../src/main/java/example/Config.java | 28 +- .../src/main/java/example/FooHandler.java | 5 +- .../src/test/java/example/MapTests.java | 2 +- .../function-sample-compiler/build.gradle | 6 +- .../function-sample-compiler/pom.xml | 8 +- .../java/com/example/SampleApplication.java | 5 +- .../example/SampleCompiledConsumerTests.java | 6 +- .../example/SampleCompiledFunctionTests.java | 4 +- .../function-sample-pof/build.gradle | 6 +- .../function-sample-pof/pom.xml | 10 +- .../src/main/java/functions/Application.java | 5 +- .../src/main/java/functions/Greeter.java | 5 +- .../function-sample-pojo/build.gradle | 6 +- .../function-sample-pojo/pom.xml | 10 +- .../com/example/LowercaseConfiguration.java | 6 +- .../java/com/example/SampleApplication.java | 36 +- .../src/main/resources/application.properties | 8 +- .../example/SampleApplicationMvcTests.java | 16 +- .../com/example/SampleApplicationTests.java | 35 +- .../function-sample-task/build.gradle | 6 +- .../function-sample-task/pom.xml | 8 +- .../java/com/example/SampleApplication.java | 5 +- .../src/main/resources/application.yml | 2 +- .../function-sample/build.gradle | 6 +- .../function-sample/pom.xml | 8 +- .../java/com/example/SampleApplication.java | 27 +- .../com/example/functions/CharCounter.java | 3 +- .../java/com/example/functions/Exclaimer.java | 5 +- .../java/com/example/functions/Greeter.java | 3 +- .../resources/META-INF/thin-rabbit.properties | 10 +- .../src/main/resources/application.properties | 4 +- .../test/java/com/example/FunctionTests.java | 21 +- .../example/SampleApplicationMvcTests.java | 4 +- .../com/example/SampleApplicationTests.java | 64 +- spring-cloud-function-samples/pom.xml | 4 +- spring-cloud-function-task/pom.xml | 4 +- .../cloud/function/task/TaskApplication.java | 11 +- .../function/task/TaskConfiguration.java | 22 +- .../task/TaskConfigurationProperties.java | 11 +- spring-cloud-function-web/pom.xml | 5 +- .../function/web/BasicStringConverter.java | 23 +- .../cloud/function/web/RequestProcessor.java | 81 +- .../cloud/function/web/RestApplication.java | 8 +- .../cloud/function/web/StringConverter.java | 3 +- .../web/constants/WebRequestConstants.java | 24 +- .../function/web/flux/FunctionController.java | 20 +- .../web/flux/FunctionHandlerMapping.java | 36 +- .../web/flux/ReactorAutoConfiguration.java | 10 +- .../function/FunctionEndpointInitializer.java | 22 +- .../function/web/mvc/FunctionController.java | 19 +- .../web/mvc/FunctionHandlerMapping.java | 33 +- .../web/mvc/ReactorAutoConfiguration.java | 9 +- .../web/source/DestinationResolver.java | 3 +- .../function/web/source/RequestBuilder.java | 6 +- .../web/source/SimpleDestinationResolver.java | 2 +- .../web/source/SimpleRequestBuilder.java | 14 +- .../web/source/SupplierAutoConfiguration.java | 8 +- .../function/web/source/SupplierExporter.java | 27 +- .../web/source/SupplierProperties.java | 24 +- .../cloud/function/web/util/HeaderUtils.java | 10 +- ...itional-spring-configuration-metadata.json | 16 +- .../main/resources/META-INF/spring.factories | 4 +- .../flux/FluxRestApplicationTests.java | 85 +- .../function/mvc/MvcRestApplicationTests.java | 80 +- .../cloud/function/scan/ComponentTests.java | 14 +- .../test/ExplicitNonFunctionalTests.java | 10 +- .../cloud/function/test/FunctionalTests.java | 12 +- .../test/FunctionalWithInputListTests.java | 12 +- .../test/FunctionalWithInputSetTests.java | 17 +- .../function/test/HeadersToMessageTests.java | 14 +- .../test/ImplicitNonFunctionalTests.java | 10 +- .../MoreThenOneFunctionRootMappingTests.java | 13 +- .../cloud/function/test/PojoTests.java | 24 +- .../web/flux/HeadersToMessageTests.java | 34 +- .../web/flux/HttpGetIntegrationTests.java | 64 +- .../web/flux/HttpPostIntegrationTests.java | 118 +-- .../cloud/function/web/flux/PrefixTests.java | 15 +- .../function/web/flux/SingletonTests.java | 15 +- .../function/web/mvc/DefaultRouteTests.java | 17 +- .../web/mvc/HeadersToMessageTests.java | 21 +- .../web/mvc/HttpGetIntegrationTests.java | 69 +- .../web/mvc/HttpPostIntegrationTests.java | 102 +-- .../cloud/function/web/mvc/PrefixTests.java | 15 +- .../function/web/mvc/SingletonTests.java | 22 +- ...urceAutoConfigurationIntegrationTests.java | 11 +- .../web/source/WebAppIntegrationTests.java | 22 +- .../src/test/resources/static/test.html | 4 +- spring-cloud-starter-function-web/pom.xml | 5 +- spring-cloud-starter-function-webflux/pom.xml | 5 +- 268 files changed, 5114 insertions(+), 3993 deletions(-) create mode 100644 .editorconfig create mode 100644 .springformat diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..0679d88a9 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = tab +indent_size = 4 +end_of_line = lf +insert_final_newline = true + +[*.yml] +indent_style = space +indent_size = 2 diff --git a/.mvn/settings.xml b/.mvn/settings.xml index f8860c9ca..2e2841999 100644 --- a/.mvn/settings.xml +++ b/.mvn/settings.xml @@ -1,15 +1,15 @@ - - - sonatype-nexus-staging - ${env.sonatype_username} - ${env.sonatype_password} - - - repo.spring.io - ${env.spring_username} - ${env.spring_password} - - + + + sonatype-nexus-staging + ${env.sonatype_username} + ${env.sonatype_password} + + + repo.spring.io + ${env.spring_username} + ${env.spring_password} + + diff --git a/.springformat b/.springformat new file mode 100644 index 000000000..e69de29bb diff --git a/docs/pom.xml b/docs/pom.xml index 2e9eabf12..f24d88df9 100644 --- a/docs/pom.xml +++ b/docs/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 spring-cloud-function-docs @@ -66,24 +66,33 @@ - + - - + + - + - - + + - + - - + + diff --git a/pipeline.yml b/pipeline.yml index bd88a461b..fbf8f9e54 100644 --- a/pipeline.yml +++ b/pipeline.yml @@ -2,75 +2,75 @@ # fly --target cloud set-pipeline --config pipeline.yml --pipeline spring-cloud-function --load-vars-from credentials.yml --- jobs: -- name: build - plan: - - get: source - trigger: true - - task: maven - config: - platform: linux - image_resource: - type: docker-image - source: - repository: springio/maven-base - inputs: - - name: source - caches: - - path: source/.m2 - run: - dir: source - path: sh - args: - - -c - - | - rm -rf ~/.m2 - ln -s $(pwd)/.m2 ~/.m2 - ./mvnw deploy -s .mvn/settings.xml -Dgpg.passphrase="${passphrase}" - params: - TERM: -dumb - passphrase: {{passphrase}} - sonatype_username: {{sonatype-username}} - sonatype_password: {{sonatype-password}} - spring_username: {{spring-username}} - spring_password: {{spring-password}} - on_failure: *slack-failure - on_success: *slack-success + - name: build + plan: + - get: source + trigger: true + - task: maven + config: + platform: linux + image_resource: + type: docker-image + source: + repository: springio/maven-base + inputs: + - name: source + caches: + - path: source/.m2 + run: + dir: source + path: sh + args: + - -c + - | + rm -rf ~/.m2 + ln -s $(pwd)/.m2 ~/.m2 + ./mvnw deploy -s .mvn/settings.xml -Dgpg.passphrase="${passphrase}" + params: + TERM: -dumb + passphrase: {{passphrase}} + sonatype_username: {{sonatype-username}} + sonatype_password: {{sonatype-password}} + spring_username: {{spring-username}} + spring_password: {{spring-password}} + on_failure: *slack-failure + on_success: *slack-success slack-failure: &slack-failure put: slack params: channel: spring-cloud-firehose attachments: - - color: danger - fallback: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME " - text: "Build has failed" - title: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME" - title_link: $ATC_EXTERNAL_URL/teams/$BUILD_TEAM_NAME/pipelines/$BUILD_PIPELINE_NAME/jobs/$BUILD_JOB_NAME/builds/$BUILD_NAME + - color: danger + fallback: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME " + text: "Build has failed" + title: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME" + title_link: $ATC_EXTERNAL_URL/teams/$BUILD_TEAM_NAME/pipelines/$BUILD_PIPELINE_NAME/jobs/$BUILD_JOB_NAME/builds/$BUILD_NAME slack-success: &slack-success put: slack params: channel: spring-cloud-firehose attachments: - - color: good - fallback: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME " - text: "Build has succeeded" - title: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME" - title_link: $ATC_EXTERNAL_URL/teams/$BUILD_TEAM_NAME/pipelines/$BUILD_PIPELINE_NAME/jobs/$BUILD_JOB_NAME/builds/$BUILD_NAME + - color: good + fallback: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME " + text: "Build has succeeded" + title: "$BUILD_PIPELINE_NAME/$BUILD_JOB_NAME #$BUILD_NAME" + title_link: $ATC_EXTERNAL_URL/teams/$BUILD_TEAM_NAME/pipelines/$BUILD_PIPELINE_NAME/jobs/$BUILD_JOB_NAME/builds/$BUILD_NAME resources: -- name: source - type: git - source: - uri: https://github.com/spring-cloud/spring-cloud-function.git -- name: slack - type: slack-notification - source: - url: {{slack-url}} - -resource_types: -- name: slack-notification - type: docker-image - source: - repository: nebhale/slack-notification-resource + - name: source + type: git + source: + uri: https://github.com/spring-cloud/spring-cloud-function.git + - name: slack + type: slack-notification + source: + url: {{slack-url}} + +resource_types: + - name: slack-notification + type: docker-image + source: + repository: nebhale/slack-notification-resource diff --git a/pom.xml b/pom.xml index e2448c746..89b6e2466 100644 --- a/pom.xml +++ b/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-cloud-function-parent @@ -13,7 +13,7 @@ org.springframework.cloud spring-cloud-build 2.1.3.BUILD-SNAPSHOT - + @@ -23,6 +23,9 @@ 2.1.0.RELEASE 1.0.15.RELEASE spring-cloud-function + true + true + @@ -91,6 +94,14 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + + + io.spring.javaformat + spring-javaformat-maven-plugin + @@ -99,7 +110,8 @@ false true - com.example,functions,example + com.example,functions,example + @@ -216,6 +228,15 @@ + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + java11+ diff --git a/spring-cloud-function-adapters/pom.xml b/spring-cloud-function-adapters/pom.xml index 675972186..0e5ac8788 100644 --- a/spring-cloud-function-adapters/pom.xml +++ b/spring-cloud-function-adapters/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 spring-cloud-function-adapter-parent @@ -18,6 +19,6 @@ spring-cloud-function-adapter-aws spring-cloud-function-adapter-openwhisk spring-cloud-function-adapter-azure - + diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/pom.xml b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/pom.xml index f77e48414..d6758afb6 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/pom.xml +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 spring-cloud-function-adapter-aws diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandler.java index 78eba99ac..06b3fc96f 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -32,7 +32,6 @@ import org.springframework.messaging.MessageHeaders; import org.springframework.messaging.support.GenericMessage; /** - * * @author Dave Syer * @author Oleg Zhurakousky * @@ -66,12 +65,12 @@ public class SpringBootApiGatewayRequestHandler extends } private boolean functionAcceptsMessage() { - return inspector.isMessage(function()); + return this.inspector.isMessage(function()); } private Object deserializeBody(String json) { try { - return mapper.readValue(json, getInputType()); + return this.mapper.readValue(json, getInputType()); } catch (Exception e) { throw new IllegalStateException("Cannot convert event", e); @@ -91,13 +90,15 @@ public class SpringBootApiGatewayRequestHandler extends protected APIGatewayProxyResponseEvent convertOutput(Object output) { if (functionReturnsMessage(output)) { Message message = (Message) output; - return new APIGatewayProxyResponseEvent().withStatusCode( - (Integer) message.getHeaders().getOrDefault("statuscode", HttpStatus.OK.value())) + return new APIGatewayProxyResponseEvent() + .withStatusCode((Integer) message.getHeaders() + .getOrDefault("statuscode", HttpStatus.OK.value())) .withHeaders(toResponseHeaders(message.getHeaders())) .withBody(serializeBody(message.getPayload())); } else { - return new APIGatewayProxyResponseEvent().withStatusCode(HttpStatus.OK.value()) + return new APIGatewayProxyResponseEvent() + .withStatusCode(HttpStatus.OK.value()) .withBody(serializeBody(output)); } @@ -116,7 +117,7 @@ public class SpringBootApiGatewayRequestHandler extends private String serializeBody(Object body) { try { - return mapper.writeValueAsString(body); + return this.mapper.writeValueAsString(body); } catch (JsonProcessingException e) { throw new IllegalStateException("Cannot convert output", e); diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java index c6771c266..38e04b6fa 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -16,8 +16,6 @@ package org.springframework.cloud.function.adapter.aws; -import static java.util.stream.Collectors.toList; - import java.util.List; import java.util.stream.Collectors; @@ -32,7 +30,11 @@ import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.messaging.Message; import org.springframework.messaging.support.GenericMessage; +import static java.util.stream.Collectors.toList; + /** + * @param payload type + * @param response type * @author Mark Fisher * @author Halvdan Hoem Grelland */ @@ -65,28 +67,26 @@ public class SpringBootKinesisEventHandler if (functionAcceptsMessage()) { return wrapInMessages(payloads); - } else { + } + else { return payloads; } } private List> wrapInMessages(List payloads) { - return payloads.stream() - .map(GenericMessage::new) - .collect(Collectors.toList()); + return payloads.stream().map(GenericMessage::new).collect(Collectors.toList()); } private List deserializePayloads(List records) { return RecordDeaggregator.deaggregate(records).stream() - .map(this::deserializeUserRecord) - .collect(toList()); + .map(this::deserializeUserRecord).collect(toList()); } @SuppressWarnings("unchecked") private E deserializeUserRecord(UserRecord userRecord) { try { byte[] jsonBytes = userRecord.getData().array(); - return (E) mapper.readValue(jsonBytes, getInputType()); + return (E) this.mapper.readValue(jsonBytes, getInputType()); } catch (Exception e) { throw new IllegalStateException("Cannot convert event", e); @@ -94,6 +94,7 @@ public class SpringBootKinesisEventHandler } private boolean functionAcceptsMessage() { - return inspector.isMessage(function()); + return this.inspector.isMessage(function()); } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java index 1610ace3d..3f795447e 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -22,12 +22,12 @@ import java.util.List; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; - import org.reactivestreams.Publisher; - import reactor.core.publisher.Flux; /** + * @param event type + * @param result types * @author Mark Fisher */ public class SpringBootRequestHandler extends SpringFunctionInitializer diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandler.java index 3230e1e7f..a04cb7a98 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017-1018 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -26,12 +26,11 @@ import java.util.List; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestStreamHandler; import com.fasterxml.jackson.databind.ObjectMapper; - import org.reactivestreams.Publisher; -import org.springframework.beans.factory.annotation.Autowired; - import reactor.core.publisher.Flux; +import org.springframework.beans.factory.annotation.Autowired; + /** * @author Dave Syer * @author Oleg Zhurakousky @@ -39,7 +38,7 @@ import reactor.core.publisher.Flux; public class SpringBootStreamHandler extends SpringFunctionInitializer implements RequestStreamHandler { - @Autowired(required=false) + @Autowired(required = false) private ObjectMapper mapper; public SpringBootStreamHandler() { @@ -64,7 +63,7 @@ public class SpringBootStreamHandler extends SpringFunctionInitializer initialize(); Object value = convertStream(input); Publisher flux = apply(extract(value)); - mapper.writeValue(output, result(value, flux)); + this.mapper.writeValue(output, result(value, flux)); } private Object result(Object input, Publisher flux) { @@ -72,7 +71,7 @@ public class SpringBootStreamHandler extends SpringFunctionInitializer for (Object value : Flux.from(flux).toIterable()) { result.add(value); } - if (isSingleValue(input) && result.size()==1) { + if (isSingleValue(input) && result.size() == 1) { return result.get(0); } return result; @@ -91,10 +90,11 @@ public class SpringBootStreamHandler extends SpringFunctionInitializer private Object convertStream(InputStream input) { try { - return mapper.readValue(input, getInputType()); + return this.mapper.readValue(input, getInputType()); } catch (Exception e) { throw new IllegalStateException("Cannot convert event", e); } } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializer.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializer.java index 0ddbd7521..8d86e0877 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializer.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -29,6 +29,7 @@ import java.util.jar.Manifest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; @@ -38,8 +39,6 @@ import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.ClassUtils; -import reactor.core.publisher.Flux; - /** * @author Dave Syer */ @@ -69,71 +68,6 @@ public class SpringFunctionInitializer implements Closeable { this(getStartClass()); } - @Override - public void close() { - if (this.context != null) { - this.context.close(); - } - } - - @SuppressWarnings("unchecked") - protected void initialize() { - if (!this.initialized.compareAndSet(false, true)) { - return; - } - logger.info("Initializing: " + configurationClass); - SpringApplication builder = springApplication(); - ConfigurableApplicationContext context = builder.run(); - context.getAutowireCapableBeanFactory().autowireBean(this); - String name = context.getEnvironment().getProperty("function.name"); - if (name == null) { - name = "function"; - } - if (this.catalog == null) { - if (context.containsBean(name)) { - this.function = context.getBean(name, Function.class); - } - } - else { - Set functionNames = this.catalog.getNames(Function.class); - if (functionNames.size() == 1) { - this.function = this.catalog.lookup(Function.class, - functionNames.iterator().next()); - } - else { - this.function = this.catalog.lookup(Function.class, name); - } - } - this.context = context; - - } - - private SpringApplication springApplication() { - Class sourceClass = configurationClass; - SpringApplication application = new org.springframework.cloud.function.context.FunctionalSpringApplication( - sourceClass); - application.setWebApplicationType(WebApplicationType.NONE); - return application; - } - - protected Class getInputType() { - if (inspector != null) { - return inspector.getInputType(function()); - } - return Object.class; - } - - protected Object function() { - return this.function; - } - - protected Publisher apply(Publisher input) { - if (this.function != null) { - return Flux.from(function.apply(input)); - } - throw new IllegalStateException("No function defined"); - } - private static Class getStartClass() { ClassLoader classLoader = SpringFunctionInitializer.class.getClassLoader(); if (System.getenv("MAIN_CLASS") != null) { @@ -180,4 +114,69 @@ public class SpringFunctionInitializer implements Closeable { return null; } + @Override + public void close() { + if (this.context != null) { + this.context.close(); + } + } + + @SuppressWarnings("unchecked") + protected void initialize() { + if (!this.initialized.compareAndSet(false, true)) { + return; + } + logger.info("Initializing: " + this.configurationClass); + SpringApplication builder = springApplication(); + ConfigurableApplicationContext context = builder.run(); + context.getAutowireCapableBeanFactory().autowireBean(this); + String name = context.getEnvironment().getProperty("function.name"); + if (name == null) { + name = "function"; + } + if (this.catalog == null) { + if (context.containsBean(name)) { + this.function = context.getBean(name, Function.class); + } + } + else { + Set functionNames = this.catalog.getNames(Function.class); + if (functionNames.size() == 1) { + this.function = this.catalog.lookup(Function.class, + functionNames.iterator().next()); + } + else { + this.function = this.catalog.lookup(Function.class, name); + } + } + this.context = context; + + } + + private SpringApplication springApplication() { + Class sourceClass = this.configurationClass; + SpringApplication application = new org.springframework.cloud.function.context.FunctionalSpringApplication( + sourceClass); + application.setWebApplicationType(WebApplicationType.NONE); + return application; + } + + protected Class getInputType() { + if (this.inspector != null) { + return this.inspector.getInputType(function()); + } + return Object.class; + } + + protected Object function() { + return this.function; + } + + protected Publisher apply(Publisher input) { + if (this.function != null) { + return Flux.from(this.function.apply(input)); + } + throw new IllegalStateException("No function defined"); + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandlerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandlerTests.java index d89b9a79e..1841a9c90 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandlerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootApiGatewayRequestHandlerTests.java @@ -1,8 +1,13 @@ package org.springframework.cloud.function.adapter.aws; +import java.util.Collections; +import java.util.Map; +import java.util.function.Function; + import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyRequestEvent; import com.amazonaws.services.lambda.runtime.events.APIGatewayProxyResponseEvent; import org.junit.Test; + import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -11,10 +16,6 @@ import org.springframework.context.annotation.Import; import org.springframework.messaging.Message; import org.springframework.messaging.support.GenericMessage; -import java.util.Collections; -import java.util.Map; -import java.util.function.Function; - import static org.assertj.core.api.Assertions.assertThat; public class SpringBootApiGatewayRequestHandlerTests { @@ -23,71 +24,83 @@ public class SpringBootApiGatewayRequestHandlerTests { @Test public void functionBean() { - handler = new SpringBootApiGatewayRequestHandler(FunctionConfig.class); - handler.initialize(); + this.handler = new SpringBootApiGatewayRequestHandler(FunctionConfig.class); + this.handler.initialize(); APIGatewayProxyRequestEvent request = new APIGatewayProxyRequestEvent(); request.setBody("{\"value\":\"foo\"}"); - Object output = handler.handleRequest(request, null); + Object output = this.handler.handleRequest(request, null); assertThat(output).isInstanceOf(APIGatewayProxyResponseEvent.class); - assertThat(((APIGatewayProxyResponseEvent) output).getStatusCode()).isEqualTo(200); - assertThat(((APIGatewayProxyResponseEvent) output).getBody()).isEqualTo("{\"value\":\"FOO\"}"); - } - - @Configuration - @Import({ContextFunctionCatalogAutoConfiguration.class, - JacksonAutoConfiguration.class}) - protected static class FunctionConfig { - @Bean - public Function function() { - return foo -> new Bar(foo.getValue().toUpperCase()); - } + assertThat(((APIGatewayProxyResponseEvent) output).getStatusCode()) + .isEqualTo(200); + assertThat(((APIGatewayProxyResponseEvent) output).getBody()) + .isEqualTo("{\"value\":\"FOO\"}"); } @Test public void functionMessageBean() { - handler = new SpringBootApiGatewayRequestHandler(FunctionMessageConfig.class); - handler.initialize(); + this.handler = new SpringBootApiGatewayRequestHandler( + FunctionMessageConfig.class); + this.handler.initialize(); APIGatewayProxyRequestEvent request = new APIGatewayProxyRequestEvent(); request.setBody("{\"value\":\"foo\"}"); - Object output = handler.handleRequest(request, null); + Object output = this.handler.handleRequest(request, null); assertThat(output).isInstanceOf(APIGatewayProxyResponseEvent.class); - assertThat(((APIGatewayProxyResponseEvent) output).getStatusCode()).isEqualTo(200); - assertThat(((APIGatewayProxyResponseEvent) output).getHeaders().get("spring")).isEqualTo("cloud"); - assertThat(((APIGatewayProxyResponseEvent) output).getBody()).isEqualTo("{\"value\":\"FOO\"}"); + assertThat(((APIGatewayProxyResponseEvent) output).getStatusCode()) + .isEqualTo(200); + assertThat(((APIGatewayProxyResponseEvent) output).getHeaders().get("spring")) + .isEqualTo("cloud"); + assertThat(((APIGatewayProxyResponseEvent) output).getBody()) + .isEqualTo("{\"value\":\"FOO\"}"); } @Configuration - @Import({ContextFunctionCatalogAutoConfiguration.class, - JacksonAutoConfiguration.class}) + @Import({ ContextFunctionCatalogAutoConfiguration.class, + JacksonAutoConfiguration.class }) + protected static class FunctionConfig { + + @Bean + public Function function() { + return foo -> new Bar(foo.getValue().toUpperCase()); + } + + } + + @Configuration + @Import({ ContextFunctionCatalogAutoConfiguration.class, + JacksonAutoConfiguration.class }) protected static class FunctionMessageConfig { + @Bean public Function, Message> function() { return (foo -> { Map headers = Collections.singletonMap("spring", "cloud"); return new GenericMessage<>( - new Bar(foo.getPayload().getValue().toUpperCase()), - headers); + new Bar(foo.getPayload().getValue().toUpperCase()), headers); }); } + } protected static class Foo { + private String value; public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } protected static class Bar { + private String value; public Bar() { @@ -98,11 +111,13 @@ public class SpringBootApiGatewayRequestHandlerTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandlerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandlerTests.java index 15f8e38f1..9824f5eb7 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandlerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootKinesisEventHandlerTests.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -16,11 +16,6 @@ package org.springframework.cloud.function.adapter.aws; -import static java.util.Arrays.asList; -import static java.util.Collections.singletonList; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; @@ -41,6 +36,11 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.messaging.Message; +import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + /** * @author Halvdan Hoem Grelland */ @@ -50,122 +50,6 @@ public class SpringBootKinesisEventHandlerTests { private SpringBootKinesisEventHandler handler; - @Test - public void functionBeanHandlesKinesisEvent() throws Exception { - handler = new SpringBootKinesisEventHandler<>(FunctionConfig.class); - handler.initialize(); - - KinesisEvent event = asKinesisEvent(singletonList(new Foo("foo"))); - - List output = handler.handleRequest(event, null); - - assertThat(output).containsExactly(new Bar("FOO")); - } - - @Test - public void functionBeanHandlesAggregatedKinesisEvent() throws Exception { - handler = new SpringBootKinesisEventHandler<>(FunctionConfig.class); - handler.initialize(); - - List events = asList(new Foo("foo"), new Foo("bar"), new Foo("baz")); - KinesisEvent aggregatedEvent = asAggregatedKinesisEvent(events); - - List output = handler.handleRequest(aggregatedEvent, null); - - assertThat(output) - .containsExactly(new Bar("FOO"), new Bar("BAR"), new Bar("BAZ")); - } - - @Test - public void functionMessageBean() throws Exception { - handler = new SpringBootKinesisEventHandler<>(FunctionMessageConfig.class); - handler.initialize(); - - KinesisEvent event = asKinesisEvent(asList(new Foo("foo"), new Foo("bar"))); - - List output = handler.handleRequest(event, null); - - assertThat(output) - .containsExactly(new Bar("FOO"), new Bar("BAR")); - } - - @Configuration - @Import({ - ContextFunctionCatalogAutoConfiguration.class, - JacksonAutoConfiguration.class - }) - protected static class FunctionConfig { - @Bean - public Function function() { - return foo -> new Bar(foo.getValue().toUpperCase()); - } - } - - @Configuration - @Import({ - ContextFunctionCatalogAutoConfiguration.class, - JacksonAutoConfiguration.class - }) - protected static class FunctionMessageConfig { - @Bean - public Function, Bar> function() { - return foo -> new Bar(foo.getPayload().getValue().toUpperCase()); - } - } - - protected static class Foo { - - private String value; - - public Foo() { - } - - public Foo(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - } - - protected static class Bar { - - private String value; - - public Bar() { - } - - public Bar(String value) { - this.value = value; - } - - public String getValue() { - return value; - } - - public void setValue(String value) { - this.value = value; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Bar bar = (Bar) o; - return Objects.equals(value, bar.value); - } - - @Override - public int hashCode() { - return Objects.hash(value); - } - } - private static KinesisEvent asKinesisEvent(List payloads) { KinesisEvent kinesisEvent = new KinesisEvent(); @@ -175,8 +59,7 @@ public class SpringBootKinesisEventHandlerTests { KinesisEvent.Record record = new KinesisEvent.Record(); record.setData(asJsonByteBuffer(payload)); - KinesisEvent.KinesisEventRecord kinesisEventRecord = - new KinesisEvent.KinesisEventRecord(); + KinesisEvent.KinesisEventRecord kinesisEventRecord = new KinesisEvent.KinesisEventRecord(); kinesisEventRecord.setKinesis(record); kinesisEventRecords.add(kinesisEventRecord); @@ -190,12 +73,12 @@ public class SpringBootKinesisEventHandlerTests { private static KinesisEvent asAggregatedKinesisEvent(List payloads) { RecordAggregator aggregator = new RecordAggregator(); - payloads.stream() - .map(SpringBootKinesisEventHandlerTests::asJsonByteBuffer) + payloads.stream().map(SpringBootKinesisEventHandlerTests::asJsonByteBuffer) .forEach(buffer -> { try { aggregator.addUserRecord("fakePartitionKey", buffer.array()); - } catch (Exception e) { + } + catch (Exception e) { fail("Creating aggregated record failed"); } }); @@ -218,9 +101,132 @@ public class SpringBootKinesisEventHandlerTests { private static ByteBuffer asJsonByteBuffer(Object object) { try { return ByteBuffer.wrap(mapper.writeValueAsBytes(object)); - } catch (JsonProcessingException e) { + } + catch (JsonProcessingException e) { fail("Setting up test data failed", e); throw new RuntimeException(e); } } + + @Test + public void functionBeanHandlesKinesisEvent() throws Exception { + this.handler = new SpringBootKinesisEventHandler<>(FunctionConfig.class); + this.handler.initialize(); + + KinesisEvent event = asKinesisEvent(singletonList(new Foo("foo"))); + + List output = this.handler.handleRequest(event, null); + + assertThat(output).containsExactly(new Bar("FOO")); + } + + @Test + public void functionBeanHandlesAggregatedKinesisEvent() throws Exception { + this.handler = new SpringBootKinesisEventHandler<>(FunctionConfig.class); + this.handler.initialize(); + + List events = asList(new Foo("foo"), new Foo("bar"), new Foo("baz")); + KinesisEvent aggregatedEvent = asAggregatedKinesisEvent(events); + + List output = this.handler.handleRequest(aggregatedEvent, null); + + assertThat(output).containsExactly(new Bar("FOO"), new Bar("BAR"), + new Bar("BAZ")); + } + + @Test + public void functionMessageBean() throws Exception { + this.handler = new SpringBootKinesisEventHandler<>(FunctionMessageConfig.class); + this.handler.initialize(); + + KinesisEvent event = asKinesisEvent(asList(new Foo("foo"), new Foo("bar"))); + + List output = this.handler.handleRequest(event, null); + + assertThat(output).containsExactly(new Bar("FOO"), new Bar("BAR")); + } + + @Configuration + @Import({ ContextFunctionCatalogAutoConfiguration.class, + JacksonAutoConfiguration.class }) + protected static class FunctionConfig { + + @Bean + public Function function() { + return foo -> new Bar(foo.getValue().toUpperCase()); + } + + } + + @Configuration + @Import({ ContextFunctionCatalogAutoConfiguration.class, + JacksonAutoConfiguration.class }) + protected static class FunctionMessageConfig { + + @Bean + public Function, Bar> function() { + return foo -> new Bar(foo.getPayload().getValue().toUpperCase()); + } + + } + + protected static class Foo { + + private String value; + + public Foo() { + } + + public Foo(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } + + } + + protected static class Bar { + + private String value; + + public Bar() { + } + + public Bar(String value) { + this.value = value; + } + + public String getValue() { + return this.value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + Bar bar = (Bar) o; + return Objects.equals(this.value, bar.value); + } + + @Override + public int hashCode() { + return Objects.hash(this.value); + } + + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandlerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandlerTests.java index f192475f0..898208d55 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandlerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -38,9 +38,9 @@ public class SpringBootRequestHandlerTests { @Test public void functionBean() throws Exception { - handler = new SpringBootRequestHandler(FunctionConfig.class); - handler.initialize(); - Object output = handler.handleRequest(new Foo("foo"), null); + this.handler = new SpringBootRequestHandler(FunctionConfig.class); + this.handler.initialize(); + Object output = this.handler.handleRequest(new Foo("foo"), null); assertThat(output).isInstanceOf(Bar.class); } @@ -48,13 +48,16 @@ public class SpringBootRequestHandlerTests { @Import({ ContextFunctionCatalogAutoConfiguration.class, JacksonAutoConfiguration.class }) protected static class FunctionConfig { + @Bean public Function function() { return foo -> new Bar(foo.getValue().toUpperCase()); } + } protected static class Foo { + private String value; public Foo(String value) { @@ -62,15 +65,17 @@ public class SpringBootRequestHandlerTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } protected static class Bar { + private String value; public Bar() { @@ -81,11 +86,13 @@ public class SpringBootRequestHandlerTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandlerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandlerTests.java index 4027e5c98..ccce8b355 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandlerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringBootStreamHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -40,21 +40,21 @@ public class SpringBootStreamHandlerTests { @Test public void functionBeanWithJacksonConfig() throws Exception { - handler = new SpringBootStreamHandler(FunctionConfigWithJackson.class); - handler.initialize(); + this.handler = new SpringBootStreamHandler(FunctionConfigWithJackson.class); + this.handler.initialize(); ByteArrayOutputStream output = new ByteArrayOutputStream(); - handler.handleRequest(new ByteArrayInputStream("{\"value\":\"foo\"}".getBytes()), - output, null); + this.handler.handleRequest( + new ByteArrayInputStream("{\"value\":\"foo\"}".getBytes()), output, null); assertThat(output.toString()).isEqualTo("{\"value\":\"FOO\"}"); } @Test public void functionBeanWithoutJacksonConfig() throws Exception { - handler = new SpringBootStreamHandler(FunctionConfigWithoutJackson.class); - handler.initialize(); + this.handler = new SpringBootStreamHandler(FunctionConfigWithoutJackson.class); + this.handler.initialize(); ByteArrayOutputStream output = new ByteArrayOutputStream(); - handler.handleRequest(new ByteArrayInputStream("{\"value\":\"foo\"}".getBytes()), - output, null); + this.handler.handleRequest( + new ByteArrayInputStream("{\"value\":\"foo\"}".getBytes()), output, null); assertThat(output.toString()).isEqualTo("{\"value\":\"FOO\"}"); } @@ -62,34 +62,41 @@ public class SpringBootStreamHandlerTests { @Import({ ContextFunctionCatalogAutoConfiguration.class, JacksonAutoConfiguration.class }) protected static class FunctionConfigWithJackson { + @Bean public Function function() { return foo -> new Bar(foo.getValue().toUpperCase()); } + } @Configuration - @Import({ ContextFunctionCatalogAutoConfiguration.class}) + @Import({ ContextFunctionCatalogAutoConfiguration.class }) protected static class FunctionConfigWithoutJackson { + @Bean public Function function() { return foo -> new Bar(foo.getValue().toUpperCase()); } + } protected static class Foo { + private String value; public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } protected static class Bar { + private String value; public Bar() { @@ -100,11 +107,13 @@ public class SpringBootStreamHandlerTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializerTests.java index c3cb96df9..96bbaba6d 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/test/java/org/springframework/cloud/function/adapter/aws/SpringFunctionInitializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,6 +23,7 @@ import java.util.stream.Collectors; import org.junit.After; import org.junit.Ignore; import org.junit.Test; +import reactor.core.publisher.Flux; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionType; @@ -35,8 +36,6 @@ import org.springframework.context.support.GenericApplicationContext; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -48,74 +47,78 @@ public class SpringFunctionInitializerTests { @After public void after() { System.clearProperty("function.name"); - if (initializer != null) { - initializer.close(); + if (this.initializer != null) { + this.initializer.close(); } } @Test public void functionBean() { - initializer = new SpringFunctionInitializer(FluxFunctionConfig.class); - initializer.initialize(); - Flux result = Flux.from(initializer.apply(Flux.just(new Foo()))); + this.initializer = new SpringFunctionInitializer(FluxFunctionConfig.class); + this.initializer.initialize(); + Flux result = Flux.from(this.initializer.apply(Flux.just(new Foo()))); assertThat(result.blockFirst()).isInstanceOf(Bar.class); } @Test public void functionApp() { - initializer = new SpringFunctionInitializer(FluxFunctionApp.class); - initializer.initialize(); - Flux result = Flux.from(initializer.apply(Flux.just(new Foo()))); + this.initializer = new SpringFunctionInitializer(FluxFunctionApp.class); + this.initializer.initialize(); + Flux result = Flux.from(this.initializer.apply(Flux.just(new Foo()))); assertThat(result.blockFirst()).isInstanceOf(Bar.class); } @Test public void functionCatalog() { - initializer = new SpringFunctionInitializer(FunctionConfig.class); - initializer.initialize(); - Flux result = Flux.from(initializer.apply(Flux.just(new Foo()))); + this.initializer = new SpringFunctionInitializer(FunctionConfig.class); + this.initializer.initialize(); + Flux result = Flux.from(this.initializer.apply(Flux.just(new Foo()))); assertThat(result.blockFirst()).isInstanceOf(Bar.class); } @Test @Ignore // related to boot 2.1 no bean override change public void functionRegistrar() { - initializer = new SpringFunctionInitializer(FunctionRegistrar.class); - initializer.initialize(); - Flux result = Flux.from(initializer.apply(Flux.just(new Foo()))); + this.initializer = new SpringFunctionInitializer(FunctionRegistrar.class); + this.initializer.initialize(); + Flux result = Flux.from(this.initializer.apply(Flux.just(new Foo()))); assertThat(result.blockFirst()).isInstanceOf(Bar.class); } @Test public void namedFunctionCatalog() { - initializer = new SpringFunctionInitializer(NamedFunctionConfig.class); + this.initializer = new SpringFunctionInitializer(NamedFunctionConfig.class); System.setProperty("function.name", "other"); - initializer.initialize(); - Flux result = Flux.from(initializer.apply(Flux.just(new Foo()))); + this.initializer.initialize(); + Flux result = Flux.from(this.initializer.apply(Flux.just(new Foo()))); assertThat(result.blockFirst()).isInstanceOf(Bar.class); } @Test public void consumerCatalog() { - initializer = new SpringFunctionInitializer(ConsumerConfig.class); - initializer.initialize(); - Flux result = Flux.from(initializer.apply(Flux.just(new Foo()))); + this.initializer = new SpringFunctionInitializer(ConsumerConfig.class); + this.initializer.initialize(); + Flux result = Flux.from(this.initializer.apply(Flux.just(new Foo()))); assertThat(result.toStream().collect(Collectors.toList())).isEmpty(); } @Configuration protected static class FluxFunctionConfig { + @Bean public Function, Flux> function() { return flux -> flux.map(foo -> new Bar()); } + } protected static class FluxFunctionApp implements Function, Flux> { + @Override public Flux apply(Flux flux) { return flux.map(foo -> new Bar()); } + } protected static class FunctionRegistrar @@ -133,39 +136,49 @@ public class SpringFunctionInitializerTests { .type(FunctionType.from(Foo.class).to(Bar.class) .wrap(Flux.class).getType())); } + } @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) protected static class FunctionConfig { + @Bean public Function function() { return foo -> new Bar(); } + } @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) protected static class NamedFunctionConfig { + @Bean public Function other() { return foo -> new Bar(); } + } @Configuration @Import(ContextFunctionCatalogAutoConfiguration.class) protected static class ConsumerConfig { + @Bean public Consumer consumer() { return foo -> { }; } + } protected static class Foo { + } protected static class Bar { + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/pom.xml b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/pom.xml index 97fa43117..0e507e8ad 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/pom.xml +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-cloud-function-adapter-azure @@ -20,7 +20,8 @@ UTF-8 UTF-8 1.8 - 1.0.0-beta-5 + 1.0.0-beta-5 + diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java index aafaeeabc..c01da04a5 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -24,12 +24,12 @@ import java.util.function.Function; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.OutputBinding; - import org.reactivestreams.Publisher; - import reactor.core.publisher.Flux; /** + * @param input type + * @param result type * @author Soby Chacko */ public class AzureSpringBootRequestHandler extends AzureSpringFunctionInitializer { @@ -118,4 +118,5 @@ public class AzureSpringBootRequestHandler extends AzureSpringFunctionInit protected O convertOutput(Object output) { return (O) output; } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java index 759880698..68f3ee808 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializer.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -29,7 +29,6 @@ import java.util.function.Function; import java.util.jar.Manifest; import com.microsoft.azure.functions.ExecutionContext; - import org.reactivestreams.Publisher; import org.springframework.beans.factory.annotation.Autowired; @@ -46,20 +45,20 @@ import org.springframework.util.ClassUtils; */ public class AzureSpringFunctionInitializer implements Closeable { + private volatile static ConfigurableApplicationContext context; + + private final Class configurationClass; + private volatile Function, Publisher> function; private AtomicBoolean initialized = new AtomicBoolean(); - private final Class configurationClass; - @Autowired(required = false) private volatile FunctionCatalog catalog; @Autowired(required = false) private volatile FunctionInspector inspector; - private volatile static ConfigurableApplicationContext context; - public AzureSpringFunctionInitializer(Class configurationClass) { this.configurationClass = configurationClass == null ? getClass() : configurationClass; @@ -69,6 +68,55 @@ public class AzureSpringFunctionInitializer implements Closeable { this(getStartClass()); } + private static Class getStartClass() { + ClassLoader classLoader = org.springframework.cloud.function.adapter.azure.AzureSpringFunctionInitializer.class + .getClassLoader(); + if (System.getenv("MAIN_CLASS") != null) { + return ClassUtils.resolveClassName(System.getenv("MAIN_CLASS"), classLoader); + } + try { + Class result = getStartClass( + Collections.list(classLoader.getResources("META-INF/MANIFEST.MF"))); + if (result == null) { + result = getStartClass(Collections + .list(classLoader.getResources("meta-inf/manifest.mf"))); + } + return result; + } + catch (Exception ex) { + return null; + } + } + + private static Class getStartClass(List list) { + for (URL url : list) { + try { + InputStream inputStream = url.openStream(); + try { + Manifest manifest = new Manifest(inputStream); + String startClass = manifest.getMainAttributes() + .getValue("Main-Class"); + if (startClass != null) { + Class aClass = ClassUtils.forName(startClass, + org.springframework.cloud.function.adapter.azure.AzureSpringFunctionInitializer.class + .getClassLoader()); + SpringBootApplication declaredAnnotation = aClass + .getDeclaredAnnotation(SpringBootApplication.class); + if (declaredAnnotation != null) { + return aClass; + } + } + } + finally { + inputStream.close(); + } + } + catch (Exception ex) { + } + } + return null; + } + @Override public void close() throws IOException { if (AzureSpringFunctionInitializer.context != null) { @@ -132,7 +180,7 @@ public class AzureSpringFunctionInitializer implements Closeable { } private SpringApplication springApplication() { - Class sourceClass = configurationClass; + Class sourceClass = this.configurationClass; SpringApplication application = new org.springframework.cloud.function.context.FunctionalSpringApplication( sourceClass); application.setWebApplicationType(WebApplicationType.NONE); @@ -144,7 +192,8 @@ public class AzureSpringFunctionInitializer implements Closeable { return true; } if (this.inspector != null) { - return Collection.class.isAssignableFrom(inspector.getInputType(function)); + return Collection.class + .isAssignableFrom(this.inspector.getInputType(function)); } return ((Collection) input).size() <= 1; } @@ -154,7 +203,8 @@ public class AzureSpringFunctionInitializer implements Closeable { return true; } if (this.inspector != null) { - return Collection.class.isAssignableFrom(inspector.getOutputType(function)); + return Collection.class + .isAssignableFrom(this.inspector.getOutputType(function)); } return ((Collection) output).size() <= 1; } @@ -174,64 +224,16 @@ public class AzureSpringFunctionInitializer implements Closeable { throw new IllegalStateException("No function defined with name=" + name); } - private static Class getStartClass() { - ClassLoader classLoader = org.springframework.cloud.function.adapter.azure.AzureSpringFunctionInitializer.class - .getClassLoader(); - if (System.getenv("MAIN_CLASS") != null) { - return ClassUtils.resolveClassName(System.getenv("MAIN_CLASS"), classLoader); - } - try { - Class result = getStartClass( - Collections.list(classLoader.getResources("META-INF/MANIFEST.MF"))); - if (result == null) { - result = getStartClass(Collections - .list(classLoader.getResources("meta-inf/manifest.mf"))); - } - return result; - } - catch (Exception ex) { - return null; - } - } - - private static Class getStartClass(List list) { - for (URL url : list) { - try { - InputStream inputStream = url.openStream(); - try { - Manifest manifest = new Manifest(inputStream); - String startClass = manifest.getMainAttributes() - .getValue("Main-Class"); - if (startClass != null) { - Class aClass = ClassUtils.forName(startClass, - org.springframework.cloud.function.adapter.azure.AzureSpringFunctionInitializer.class - .getClassLoader()); - SpringBootApplication declaredAnnotation = aClass - .getDeclaredAnnotation(SpringBootApplication.class); - if (declaredAnnotation != null) { - return aClass; - } - } - } - finally { - inputStream.close(); - } - } - catch (Exception ex) { - } - } - return null; - } - public Function, Publisher> getFunction() { - return function; + return this.function; } public FunctionCatalog getCatalog() { - return catalog; + return this.catalog; } public FunctionInspector getInspector() { - return inspector; + return this.inspector; } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandlerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandlerTests.java index 2e10a8dd3..09090dcae 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandlerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandlerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -24,6 +24,7 @@ import java.util.stream.Collectors; import org.junit.After; import org.junit.Test; +import reactor.core.publisher.Flux; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.context.annotation.Bean; @@ -31,8 +32,6 @@ import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -114,50 +113,60 @@ public class AzureSpringBootRequestHandlerTests { @After public void close() throws IOException { - if (handler != null) - handler.close(); + if (this.handler != null) { + this.handler.close(); + } } @Configuration protected static class BareConfig { + @Bean public Function, Flux> function() { return foos -> foos.map(foo -> new Bar(foo.getValue().toUpperCase())); } + } @Configuration @EnableAutoConfiguration protected static class AutoConfig { + @Bean public Function uppercase() { return foo -> new Bar(foo.getValue().toUpperCase()); } + } @Configuration @EnableAutoConfiguration protected static class ListConfig { + @Bean public Function, List> uppercase() { return foos -> foos.stream().map(foo -> new Bar(foo.getValue().toUpperCase())) .collect(Collectors.toList()); } + } @Configuration @EnableAutoConfiguration protected static class CollectConfig { + @Bean public Function, Bar> uppercase() { return foos -> new Bar(foos.stream().map(foo -> foo.getValue().toUpperCase()) .collect(Collectors.joining(","))); } + } @Configuration @EnableAutoConfiguration protected static class MultiConfig { + @Bean public Function uppercase() { return foo -> new Bar(foo.getValue().toUpperCase()); @@ -167,6 +176,7 @@ public class AzureSpringBootRequestHandlerTests { public Function lowercase() { return bar -> new Foo(bar.getValue().toLowerCase()); } + } } @@ -178,25 +188,26 @@ class Foo { Foo() { } - public String lowercase() { - return value.toLowerCase(); - } - public Foo(String value) { this.value = value; } + public String lowercase() { + return this.value.toLowerCase(); + } + public String uppercase() { - return value.toUpperCase(); + return this.value.toUpperCase(); } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } class Bar { @@ -211,11 +222,11 @@ class Bar { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializerTests.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializerTests.java index d5e623cf0..f50d44752 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializerTests.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/AzureSpringFunctionInitializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.After; import org.junit.Test; +import reactor.core.publisher.Flux; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -31,8 +32,6 @@ import org.springframework.context.support.GenericApplicationContext; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -50,8 +49,9 @@ public class AzureSpringFunctionInitializerTests { @After public void close() throws IOException { - if (handler != null) - handler.close(); + if (this.handler != null) { + this.handler.close(); + } } @Test @@ -84,18 +84,22 @@ public class AzureSpringFunctionInitializerTests { @SpringBootConfiguration @EnableAutoConfiguration protected static class BareConfig { + @Bean public Function function() { return foo -> new Bar(foo.getValue().toUpperCase()); } + } @SpringBootConfiguration protected static class FunctionConfig implements Function { + @Override public Bar apply(Foo foo) { return new Bar(foo.getValue().toUpperCase()); } + } @SpringBootConfiguration @@ -113,5 +117,7 @@ public class AzureSpringFunctionInitializerTests { "uppercase") .type(FunctionType.from(Foo.class).to(Bar.class))); } + } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/TestExecutionContext.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/TestExecutionContext.java index d7cf5ff17..a8ab79fbf 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/TestExecutionContext.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/test/java/org/springframework/cloud/function/adapter/azure/TestExecutionContext.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,7 @@ import java.util.logging.Logger; import com.microsoft.azure.functions.ExecutionContext; public class TestExecutionContext implements ExecutionContext { + private String name; public TestExecutionContext(String name) { @@ -40,6 +41,7 @@ public class TestExecutionContext implements ExecutionContext { @Override public String getFunctionName() { - return name; + return this.name; } -} \ No newline at end of file + +} diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/pom.xml b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/pom.xml index ebeabc392..cc716bb68 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/pom.xml +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 spring-cloud-function-adapter-openwhisk diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/FunctionProperties.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/FunctionProperties.java index b3aeeef17..89b7e38d9 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/FunctionProperties.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/FunctionProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -29,7 +29,7 @@ public class FunctionProperties { private String type = "function"; public String getName() { - return name; + return this.name; } public void setName(String name) { @@ -37,10 +37,11 @@ public class FunctionProperties { } public String getType() { - return type; + return this.type; } public void setType(String type) { this.type = type; } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionApplication.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionApplication.java index 456975d0d..928b7cbe0 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionApplication.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,6 +23,7 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties /** * @author Mark Fisher */ +// @checkstyle:off @SpringBootApplication @EnableConfigurationProperties(FunctionProperties.class) public class OpenWhiskActionApplication { @@ -30,4 +31,6 @@ public class OpenWhiskActionApplication { public static void main(String[] args) { SpringApplication.run(OpenWhiskActionApplication.class, args); } + } +// @checkstyle:on diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandler.java index 6f40f720b..c03ea3c92 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,18 +23,16 @@ import java.util.Map; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; - import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; -import reactor.core.publisher.Flux; - /** * @author Mark Fisher * @author Kamesh Sampath @@ -43,6 +41,7 @@ import reactor.core.publisher.Flux; public class OpenWhiskActionHandler extends OpenWhiskFunctionInitializer { private static final String NO_INPUT_PROVIDED = "No input provided"; + private static Log logger = LogFactory.getLog(OpenWhiskFunctionInitializer.class); @Autowired @@ -61,7 +60,7 @@ public class OpenWhiskActionHandler extends OpenWhiskFunctionInitializer { public Object run(@RequestBody OpenWhiskActionRequest request) { Object input = convertEvent(request.getValue()); Object result = NO_INPUT_PROVIDED; - if(input !=null ) { + if (input != null) { Publisher output = apply(extract(input)); result = result(input, output); } @@ -104,17 +103,20 @@ public class OpenWhiskActionHandler extends OpenWhiskFunctionInitializer { private Object convertToFunctionParamType(Object payload) { try { - return mapper.convertValue(payload, getInputType()); - } catch (Exception e) { + return this.mapper.convertValue(payload, getInputType()); + } + catch (Exception e) { throw new IllegalStateException("Cannot convert event payload", e); } } private String serializeBody(Object body) { try { - return "{\"result\":" + mapper.writeValueAsString(body) + "}"; - } catch (JsonProcessingException e) { + return "{\"result\":" + this.mapper.writeValueAsString(body) + "}"; + } + catch (JsonProcessingException e) { throw new IllegalStateException("Cannot convert output", e); } } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionRequest.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionRequest.java index 55339c57b..bda58e154 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionRequest.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -41,7 +41,7 @@ public class OpenWhiskActionRequest { private Map value; public String getActionName() { - return actionName; + return this.actionName; } public void setActionName(String actionName) { @@ -49,7 +49,7 @@ public class OpenWhiskActionRequest { } public String getActivationId() { - return activationId; + return this.activationId; } public void setActivationId(String activationId) { @@ -57,7 +57,7 @@ public class OpenWhiskActionRequest { } public String getApiKey() { - return apiKey; + return this.apiKey; } public void setApiKey(String apiKey) { @@ -65,7 +65,7 @@ public class OpenWhiskActionRequest { } public String getDeadline() { - return deadline; + return this.deadline; } public void setDeadline(String deadline) { @@ -73,7 +73,7 @@ public class OpenWhiskActionRequest { } public String getNamespace() { - return namespace; + return this.namespace; } public void setNamespace(String namespace) { @@ -81,10 +81,11 @@ public class OpenWhiskActionRequest { } public Map getValue() { - return value; + return this.value; } public void setValue(Map value) { this.value = value; } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskFunctionInitializer.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskFunctionInitializer.java index a151c0298..7f66a07bd 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskFunctionInitializer.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskFunctionInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -24,13 +24,12 @@ import java.util.function.Supplier; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.catalog.FunctionInspector; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @author Mark Fisher @@ -76,8 +75,8 @@ public class OpenWhiskFunctionInitializer { } protected Class getInputType() { - if (inspector != null) { - return inspector.getInputType(function()); + if (this.inspector != null) { + return this.inspector.getInputType(function()); } return Object.class; } @@ -89,7 +88,7 @@ public class OpenWhiskFunctionInitializer { protected Publisher apply(Publisher input) { if (this.function != null) { - return function.apply(input); + return this.function.apply(input); } if (this.consumer != null) { this.consumer.accept(input); @@ -100,4 +99,5 @@ public class OpenWhiskFunctionInitializer { } throw new IllegalStateException("No function defined"); } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskInitRequest.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskInitRequest.java index 34a75a88d..aa8b07d8f 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskInitRequest.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/main/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskInitRequest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -28,7 +28,7 @@ public class OpenWhiskInitRequest { private String main; public String getName() { - return name; + return this.name; } public void setName(String name) { @@ -36,7 +36,7 @@ public class OpenWhiskInitRequest { } public boolean isBinary() { - return binary; + return this.binary; } public void setBinary(boolean binary) { @@ -44,10 +44,11 @@ public class OpenWhiskInitRequest { } public String getMain() { - return main; + return this.main; } public void setMain(String main) { this.main = main; } + } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandlerTest.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandlerTest.java index 79ab0946c..229ab8067 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandlerTest.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/java/org/springframework/cloud/function/adapter/openwhisk/OpenWhiskActionHandlerTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -21,7 +21,6 @@ import java.util.Map; import java.util.function.Function; import com.fasterxml.jackson.databind.ObjectMapper; - import org.junit.Test; import org.junit.runner.RunWith; @@ -61,11 +60,11 @@ public class OpenWhiskActionHandlerTest { testData.put("name", "Spring"); Map eventData = new HashMap<>(); eventData.put("payload", testData); - actionHandler.init(new OpenWhiskInitRequest()); + this.actionHandler.init(new OpenWhiskInitRequest()); OpenWhiskActionRequest actionRequest = new OpenWhiskActionRequest(); actionRequest.setActionName("test_action"); actionRequest.setValue(eventData); - Object result = actionHandler.run(actionRequest); + Object result = this.actionHandler.run(actionRequest); assertNotNull(result); assertEquals("{\"result\":{\"name\":\"Spring\",\"message\":\"Hello, Spring\"}}", result); @@ -75,10 +74,10 @@ public class OpenWhiskActionHandlerTest { public void testHandlerWithoutPayload() { Map testData = new HashMap<>(); testData.put("name", "Spring"); - actionHandler.init(new OpenWhiskInitRequest()); + this.actionHandler.init(new OpenWhiskInitRequest()); OpenWhiskActionRequest actionRequest = new OpenWhiskActionRequest(); actionRequest.setActionName("test_action"); - Object result = actionHandler.run(actionRequest); + Object result = this.actionHandler.run(actionRequest); assertNotNull(result); assertEquals("{\"result\":\"No input provided\"}", result); } @@ -111,6 +110,7 @@ public class OpenWhiskActionHandlerTest { private final String GREETINGS_FORMAT = "Hello, %s"; private String name; + private String message; public Greetings() { @@ -122,21 +122,22 @@ public class OpenWhiskActionHandlerTest { } public String getMessage() { - return message; + return this.message; } public void setMessage(String message) { - this.message = String.format(GREETINGS_FORMAT, - this.name != null ? name : "nobody"); + this.message = String.format(this.GREETINGS_FORMAT, + this.name != null ? this.name : "nobody"); } public String getName() { - return name; + return this.name; } public void setName(String name) { this.name = name; } + } } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/resources/application-test.properties b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/resources/application-test.properties index 07b9a8b74..de376ab09 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/resources/application-test.properties +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-openwhisk/src/test/resources/application-test.properties @@ -1,2 +1,2 @@ -function.name: greeter -function.type: function \ No newline at end of file +function.name:greeter +function.type:function diff --git a/spring-cloud-function-compiler/pom.xml b/spring-cloud-function-compiler/pom.xml index da7578daf..df47810da 100644 --- a/spring-cloud-function-compiler/pom.xml +++ b/spring-cloud-function-compiler/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 spring-cloud-function-compiler diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/AbstractFunctionCompiler.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/AbstractFunctionCompiler.java index 598736b22..f0d01d202 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/AbstractFunctionCompiler.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/AbstractFunctionCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -30,24 +30,25 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** + * @param result type * @author Andy Clement * @author Mark Fisher * @author Oleg Zhurakousky */ public abstract class AbstractFunctionCompiler { - private static Logger logger = LoggerFactory - .getLogger(AbstractFunctionCompiler.class); - // Newlines in the property are escaped private static final String NEWLINE_ESCAPE = Matcher.quoteReplacement("\\n"); // Individual double-quote characters are represented by two double quotes in the DSL private static final String DOUBLE_DOUBLE_QUOTE = Matcher.quoteReplacement("\"\""); + private static Logger logger = LoggerFactory + .getLogger(AbstractFunctionCompiler.class); + /** * The user supplied code snippet is inserted into the template and then the result is - * compiled + * compiled. */ // @formatter:off private static String SOURCE_CODE_TEMPLATE = "package " @@ -62,11 +63,6 @@ public abstract class AbstractFunctionCompiler { + " }\n" + "}\n"; // @formatter:on - - static enum ResultType { - Consumer, Function, Supplier - } - private final ResultType resultType; private final String[] defaultResultTypeParameterizations; @@ -79,6 +75,11 @@ public abstract class AbstractFunctionCompiler { this.defaultResultTypeParameterizations = defaultResultTypeParameterizations; } + private static String decode(String input) { + return input.replaceAll(NEWLINE_ESCAPE, "\n").replaceAll(DOUBLE_DOUBLE_QUOTE, + "\""); + } + /** * Produce a factory instance by: *
    @@ -90,7 +91,9 @@ public abstract class AbstractFunctionCompiler { * Function, or Supplier instance *
  • Returning that instance. *
- * + * @param name - name of the function + * @param code - code of the function + * @param resultTypeParameterizations - result types * @return a factory instance */ public final CompiledFunctionFactory compile(String name, String code, @@ -106,14 +109,15 @@ public abstract class AbstractFunctionCompiler { code = code.substring(1, code.length() - 1); } if (!code.startsWith("return ") && !code.endsWith(";")) { - code = String.format("return (%s<%s> & java.io.Serializable) %s;", resultType, + code = String.format("return (%s<%s> & java.io.Serializable) %s;", + this.resultType, StringUtils.arrayToCommaDelimitedString(parameterizedTypes), code); } logger.info("Processed code property value :\n{}\n", code); String firstLetter = name.substring(0, 1).toUpperCase(); name = (name.length() > 1) ? firstLetter + name.substring(1) : firstLetter; String className = String.format("%s.%s%sFactory", - this.getClass().getPackage().getName(), name, resultType); + this.getClass().getPackage().getName(), name, this.resultType); CompilationResult compilationResult = buildAndCompileSourceCode(className, code, parameterizedTypes); if (compilationResult.wasSuccessful()) { @@ -129,7 +133,6 @@ public abstract class AbstractFunctionCompiler { /** * Implementing subclasses may override this, e.g. to set the input and/or output * types. - * * @param factory the {@link CompiledFunctionFactory} produced by * {@link #compile(String, String, String...)} * @return the post-processed {@link CompiledFunctionFactory} @@ -145,7 +148,6 @@ public abstract class AbstractFunctionCompiler { * specified parameterized type. This method can return more than one class if the * method body includes local class declarations. An example methodBody would be * return input -> input.buffer(5).map(list->list.get(0));. - * * @param className the name of the class * @param methodBody the source code for a method * @param parameterizedTypes the array of String representations for the parameterized @@ -157,18 +159,12 @@ public abstract class AbstractFunctionCompiler { String methodBody, String[] parameterizedTypes) { String sourceCode = makeSourceClassDefinition(className, methodBody, parameterizedTypes); - return compiler.compile(className, sourceCode); - } - - private static String decode(String input) { - return input.replaceAll(NEWLINE_ESCAPE, "\n").replaceAll(DOUBLE_DOUBLE_QUOTE, - "\""); + return this.compiler.compile(className, sourceCode); } /** * Make a full source code definition for a class by applying the specified method * body to the Reactive template. - * * @param className the name of the class * @param methodBody the code to insert into the Reactive source class template * @param types the parameterized input and/or output types as Strings @@ -177,9 +173,17 @@ public abstract class AbstractFunctionCompiler { private String makeSourceClassDefinition(String className, String methodBody, String[] types) { String shortClassName = className.substring(className.lastIndexOf('.') + 1); - String s = String.format(SOURCE_CODE_TEMPLATE, shortClassName, resultType, - resultType, StringUtils.arrayToCommaDelimitedString(types), methodBody); + String s = String.format(SOURCE_CODE_TEMPLATE, shortClassName, this.resultType, + this.resultType, StringUtils.arrayToCommaDelimitedString(types), + methodBody); logger.info("\n" + s); return s; } + + enum ResultType { + + Consumer, Function, Supplier + + } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompilationResultFactory.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompilationResultFactory.java index 5a4a6a46d..7937aa282 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompilationResultFactory.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompilationResultFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -17,6 +17,7 @@ package org.springframework.cloud.function.compiler; /** + * @param result type * @author Mark Fisher */ public interface CompilationResultFactory { diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompiledFunctionFactory.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompiledFunctionFactory.java index c7a5797bc..b383dab03 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompiledFunctionFactory.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/CompiledFunctionFactory.java @@ -1,12 +1,12 @@ /* - * Copyright 2016-2017 the original author or authors. - * + * Copyright 2012-2019 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. @@ -24,6 +24,7 @@ import org.springframework.cloud.function.compiler.java.CompilationResult; import org.springframework.util.ReflectionUtils; /** + * @param result type * @author Mark Fisher */ public class CompiledFunctionFactory implements CompilationResultFactory { @@ -79,15 +80,15 @@ public class CompiledFunctionFactory implements CompilationResultFactory { } public T getResult() { - return result; + return this.result; } public Method getFactoryMethod() { - return method; + return this.method; } public String getInputType() { - return inputType; + return this.inputType; } public void setInputType(String inputType) { @@ -95,7 +96,7 @@ public class CompiledFunctionFactory implements CompilationResultFactory { } public String getOutputType() { - return outputType; + return this.outputType; } public void setOutputType(String outputType) { @@ -103,6 +104,7 @@ public class CompiledFunctionFactory implements CompilationResultFactory { } public byte[] getGeneratedClassBytes() { - return generatedClassBytes; + return this.generatedClassBytes; } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/ConsumerCompiler.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/ConsumerCompiler.java index 9fa74749d..0db2ad16b 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/ConsumerCompiler.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/ConsumerCompiler.java @@ -1,12 +1,12 @@ /* - * Copyright 2016-2017 the original author or authors. - * + * Copyright 2012-2019 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. @@ -19,6 +19,7 @@ package org.springframework.cloud.function.compiler; import java.util.function.Consumer; /** + * @param result type * @author Mark Fisher */ public class ConsumerCompiler extends AbstractFunctionCompiler> { @@ -35,8 +36,10 @@ public class ConsumerCompiler extends AbstractFunctionCompiler> { } @Override - protected CompiledFunctionFactory> postProcessCompiledFunctionFactory(CompiledFunctionFactory> factory) { + protected CompiledFunctionFactory> postProcessCompiledFunctionFactory( + CompiledFunctionFactory> factory) { factory.setInputType(this.inputType); return factory; } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/FunctionCompiler.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/FunctionCompiler.java index 8431efd97..4dbffd6e1 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/FunctionCompiler.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/FunctionCompiler.java @@ -1,12 +1,12 @@ /* - * Copyright 2016-2017 the original author or authors. - * + * Copyright 2012-2019 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. @@ -19,6 +19,8 @@ package org.springframework.cloud.function.compiler; import java.util.function.Function; /** + * @param function input type + * @param function output type * @author Mark Fisher */ public class FunctionCompiler extends AbstractFunctionCompiler> { @@ -42,10 +44,12 @@ public class FunctionCompiler extends AbstractFunctionCompiler> postProcessCompiledFunctionFactory(CompiledFunctionFactory> factory) { + protected CompiledFunctionFactory> postProcessCompiledFunctionFactory( + CompiledFunctionFactory> factory) { factory.setInputType(this.inputType); factory.setOutputType(this.outputType); - + return factory; } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/SupplierCompiler.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/SupplierCompiler.java index 16393fcd9..fc29f0a41 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/SupplierCompiler.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/SupplierCompiler.java @@ -1,12 +1,12 @@ /* - * Copyright 2016-2017 the original author or authors. - * + * Copyright 2012-2019 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. @@ -19,6 +19,7 @@ package org.springframework.cloud.function.compiler; import java.util.function.Supplier; /** + * @param input type * @author Mark Fisher */ public class SupplierCompiler extends AbstractFunctionCompiler> { @@ -35,8 +36,10 @@ public class SupplierCompiler extends AbstractFunctionCompiler> { } @Override - protected CompiledFunctionFactory> postProcessCompiledFunctionFactory(CompiledFunctionFactory> factory) { + protected CompiledFunctionFactory> postProcessCompiledFunctionFactory( + CompiledFunctionFactory> factory) { factory.setOutputType(this.outputType); return factory; } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompiledFunctionRegistry.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompiledFunctionRegistry.java index 1832eb4d2..a81903464 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompiledFunctionRegistry.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompiledFunctionRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,8 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import reactor.core.publisher.Flux; + import org.springframework.cloud.function.compiler.AbstractFunctionCompiler; import org.springframework.cloud.function.compiler.CompiledFunctionFactory; import org.springframework.cloud.function.compiler.ConsumerCompiler; @@ -30,8 +32,6 @@ import org.springframework.cloud.function.compiler.SupplierCompiler; import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; -import reactor.core.publisher.Flux; - /** * @author Mark Fisher * @author Oleg Zhurakousky @@ -78,29 +78,35 @@ public class CompiledFunctionRegistry { } public void registerSupplier(String name, String lambda, String type) { - this.doRegister(this.supplierCompiler, this.supplierDirectory, name, lambda, type); + this.doRegister(this.supplierCompiler, this.supplierDirectory, name, lambda, + type); } public void registerFunction(String name, String lambda, String... types) { - this.doRegister(this.functionCompiler, this.functionDirectory, name, lambda, types); + this.doRegister(this.functionCompiler, this.functionDirectory, name, lambda, + types); } public void registerConsumer(String name, String lambda, String type) { - this.doRegister(this.consumerCompiler, this.consumerDirectory, name, lambda, type); + this.doRegister(this.consumerCompiler, this.consumerDirectory, name, lambda, + type); } - private void doRegister(AbstractFunctionCompiler compiler, File directory, String name, String lambda, String... types) { + private void doRegister(AbstractFunctionCompiler compiler, File directory, + String name, String lambda, String... types) { CompiledFunctionFactory factory = compiler.compile(name, lambda, types); File file = new File(directory, fileName(name)); try { FileCopyUtils.copy(factory.getGeneratedClassBytes(), file); } catch (IOException e) { - throw new IllegalArgumentException(String.format("failed to register '%s'", name), e); + throw new IllegalArgumentException( + String.format("failed to register '%s'", name), e); } } private String fileName(String functionName) { return String.format("%s.%s", functionName, "fun"); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerApplication.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerApplication.java index 6142683c9..e3695afb5 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerApplication.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,10 +19,13 @@ package org.springframework.cloud.function.compiler.app; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +// @checkstyle:off @SpringBootApplication public class CompilerApplication { public static void main(String[] args) { SpringApplication.run(CompilerApplication.class, args); } + } +// @checkstyle:on diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerController.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerController.java index 14f6c3b02..c54f66cb1 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerController.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/app/CompilerController.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -32,20 +32,21 @@ public class CompilerController { @PostMapping(path = "/supplier/{name}") public void registerSupplier(@PathVariable String name, @RequestBody String lambda, - @RequestParam(defaultValue="Flux") String type) { + @RequestParam(defaultValue = "Flux") String type) { this.registry.registerSupplier(name, lambda, type); } @PostMapping(path = "/function/{name}") public void registerFunction(@PathVariable String name, @RequestBody String lambda, - @RequestParam(defaultValue="Flux") String inputType, - @RequestParam(defaultValue="Flux") String outputType) { + @RequestParam(defaultValue = "Flux") String inputType, + @RequestParam(defaultValue = "Flux") String outputType) { this.registry.registerFunction(name, lambda, inputType, outputType); } @PostMapping(path = "/consumer/{name}") public void registerConsumer(@PathVariable String name, @RequestBody String lambda, - @RequestParam(defaultValue="Flux") String type) { + @RequestParam(defaultValue = "Flux") String type) { this.registry.registerConsumer(name, lambda, type); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/config/FunctionProxyApplicationListener.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/config/FunctionProxyApplicationListener.java index be2d62041..7adc499c0 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/config/FunctionProxyApplicationListener.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/config/FunctionProxyApplicationListener.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -73,11 +73,11 @@ public class FunctionProxyApplicationListener private final Map imports = new HashMap<>(); public Map getCompile() { - return compile; + return this.compile; } public Map getImports() { - return imports; + return this.imports; } @Override @@ -86,7 +86,7 @@ public class FunctionProxyApplicationListener DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context .getBeanFactory(); bind(context); - for (Map.Entry entry : compile.entrySet()) { + for (Map.Entry entry : this.compile.entrySet()) { String name = entry.getKey(); @SuppressWarnings("unchecked") Map properties = (Map) entry.getValue(); @@ -101,7 +101,7 @@ public class FunctionProxyApplicationListener registerLambdaCompilingProxy(name, type, inputType, outputType, lambda, beanFactory); } - for (Map.Entry entry : imports.entrySet()) { + for (Map.Entry entry : this.imports.entrySet()) { String name = entry.getKey(); @SuppressWarnings("unchecked") Map properties = (Map) entry.getValue(); @@ -132,7 +132,8 @@ public class FunctionProxyApplicationListener ConfigurationPropertiesBindingPostProcessor post) { StaticApplicationContext other = new StaticApplicationContext(); other.setEnvironment(context.getEnvironment()); - other.registerSingleton(ConfigurationBeanFactoryMetadata.class.getName(), ConfigurationBeanFactoryMetadata.class); + other.registerSingleton(ConfigurationBeanFactoryMetadata.class.getName(), + ConfigurationBeanFactoryMetadata.class); other.setParent(context); post.setApplicationContext(other); } @@ -195,4 +196,5 @@ public class FunctionProxyApplicationListener beanDefinition.setPropertyValues(props); beanFactory.registerBeanDefinition(name, beanDefinition); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CloseableFilterableJavaFileObjectIterable.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CloseableFilterableJavaFileObjectIterable.java index 29833a728..de0e4fe08 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CloseableFilterableJavaFileObjectIterable.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CloseableFilterableJavaFileObjectIterable.java @@ -1,12 +1,12 @@ /* - * Copyright 2018 the original author or authors. - * + * Copyright 2012-2019 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. @@ -23,17 +23,19 @@ import javax.tools.JavaFileObject; import org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager.CompilationInfoCache; /** - * Common superclass for iterables that need to handle closing when finished - * with and that need to handle possible constraints on the values that - * are iterated over. - * + * Common superclass for iterables that need to handle closing when finished with and that + * need to handle possible constraints on the values that are iterated over. + * * @author Andy Clement */ -public abstract class CloseableFilterableJavaFileObjectIterable implements Iterable { +public abstract class CloseableFilterableJavaFileObjectIterable + implements Iterable { -// private final static Logger logger = LoggerFactory.getLogger(CloseableFilterableJavaFileObjectIterable.class); + // private final static Logger logger = + // LoggerFactory.getLogger(CloseableFilterableJavaFileObjectIterable.class); private final static boolean BOOT_PACKAGING_AWARE = true; + private final static String BOOT_PACKAGING_PREFIX_FOR_CLASSES = "BOOT-INF/classes/"; // If set specifies the package the iterator consumer is interested in. Only @@ -44,58 +46,72 @@ public abstract class CloseableFilterableJavaFileObjectIterable implements Itera // Indicates whether the consumer of the iterator wants to see classes // that are in subpackages of those matching the filter. protected boolean includeSubpackages; - + protected CompilationInfoCache compilationInfoCache; - public CloseableFilterableJavaFileObjectIterable(CompilationInfoCache compilationInfoCache, String packageNameFilter, boolean includeSubpackages) { - if (packageNameFilter!=null && packageNameFilter.contains(File.separator)) { - throw new IllegalArgumentException("Package name filters should use dots to separate components: "+packageNameFilter); + public CloseableFilterableJavaFileObjectIterable( + CompilationInfoCache compilationInfoCache, String packageNameFilter, + boolean includeSubpackages) { + if (packageNameFilter != null && packageNameFilter.contains(File.separator)) { + throw new IllegalArgumentException( + "Package name filters should use dots to separate components: " + + packageNameFilter); } this.compilationInfoCache = compilationInfoCache; // Normalize filter to forward slashes - this.packageNameFilter = packageNameFilter==null?null:packageNameFilter.replace('.', '/') + '/'; + this.packageNameFilter = packageNameFilter == null ? null + : packageNameFilter.replace('.', '/') + '/'; this.includeSubpackages = includeSubpackages; } /** * Used by subclasses to check values against any specified constraints. - * * @param name the name to check against the criteria * @return true if the name is a valid iterator result based on the specified criteria */ protected boolean accept(String name) { -// logger.debug("checking {} against constraints packageNameFilter={} includeSubpackages={}",name,packageNameFilter,includeSubpackages); + // logger.debug("checking {} against constraints packageNameFilter={} + // includeSubpackages={}",name,packageNameFilter,includeSubpackages); if (!name.endsWith(".class")) { return false; } - if (packageNameFilter == null) { + if (this.packageNameFilter == null) { return true; } boolean accept; - // Normalize to forward slashes (some jars are producing paths with forward slashes, some with backward slashes) + // Normalize to forward slashes (some jars are producing paths with forward + // slashes, some with backward slashes) name = name.replace('\\', '/'); - if (packageNameFilter.length() == 1 && packageNameFilter.equals("/")) { + if (this.packageNameFilter.length() == 1 && this.packageNameFilter.equals("/")) { // This is the 'default package' filter representation if (name.indexOf('/') == -1) { accept = true; - } else if (BOOT_PACKAGING_AWARE) { - accept = name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES) && - name.indexOf('/',BOOT_PACKAGING_PREFIX_FOR_CLASSES.length()) == -1; + } + else if (BOOT_PACKAGING_AWARE) { + accept = name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES) && name + .indexOf('/', BOOT_PACKAGING_PREFIX_FOR_CLASSES.length()) == -1; } return accept; } - if (includeSubpackages == true) { - accept = name.startsWith(packageNameFilter); + if (this.includeSubpackages) { + accept = name.startsWith(this.packageNameFilter); if (!accept && BOOT_PACKAGING_AWARE) { - accept = name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES) && - name.indexOf(packageNameFilter)==BOOT_PACKAGING_PREFIX_FOR_CLASSES.length(); + accept = name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES) + && name.indexOf( + this.packageNameFilter) == BOOT_PACKAGING_PREFIX_FOR_CLASSES + .length(); } - } else { - accept = name.startsWith(packageNameFilter) && name.indexOf("/",packageNameFilter.length())==-1; + } + else { + accept = name.startsWith(this.packageNameFilter) + && name.indexOf("/", this.packageNameFilter.length()) == -1; if (!accept && BOOT_PACKAGING_AWARE) { - accept = name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES) && - name.indexOf(packageNameFilter)==BOOT_PACKAGING_PREFIX_FOR_CLASSES.length() && - name.indexOf("/",BOOT_PACKAGING_PREFIX_FOR_CLASSES.length()+packageNameFilter.length())==-1; + accept = name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES) + && name.indexOf( + this.packageNameFilter) == BOOT_PACKAGING_PREFIX_FOR_CLASSES + .length() + && name.indexOf("/", BOOT_PACKAGING_PREFIX_FOR_CLASSES.length() + + this.packageNameFilter.length()) == -1; } } return accept; @@ -105,4 +121,4 @@ public abstract class CloseableFilterableJavaFileObjectIterable implements Itera abstract void reset(); -} \ No newline at end of file +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationFailedException.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationFailedException.java index cc7e655ff..dcf1b8b73 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationFailedException.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationFailedException.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -38,4 +38,5 @@ public class CompilationFailedException extends RuntimeException { } return sb.toString(); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationMessage.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationMessage.java index f8aa1c6e0..add6f621c 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationMessage.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationMessage.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -17,32 +17,33 @@ package org.springframework.cloud.function.compiler.java; /** - * Encapsulate information produced during compilation. A message may be an error - * or something less serious (warning/informational). The toString() method - * will produce a formatted error include source context indicating the precise - * location of the problem. - * + * Encapsulate information produced during compilation. A message may be an error or + * something less serious (warning/informational). The toString() method will + * produce a formatted error include source context indicating the precise location of the + * problem. + * * @author Andy Clement */ public class CompilationMessage { - + private Kind kind; + private String message; + private String sourceCode; + private int startPosition; + private int endPosition; - enum Kind { - ERROR, OTHER - }; - - public CompilationMessage(Kind kind, String message, String sourceCode, int startPosition, int endPosition) { + public CompilationMessage(Kind kind, String message, String sourceCode, + int startPosition, int endPosition) { this.kind = kind; this.message = message; this.sourceCode = sourceCode; this.startPosition = startPosition; this.endPosition = endPosition; - } + }; /** * @return the type of message @@ -82,32 +83,33 @@ public class CompilationMessage { public String toString() { StringBuilder s = new StringBuilder(); s.append("==========\n"); - if (sourceCode != null) { // Cannot include source context if no source available - int[] lineStartEnd = getLineStartEnd(startPosition); - s.append(sourceCode.substring(lineStartEnd[0], lineStartEnd[1])).append("\n"); + if (this.sourceCode != null) { // Cannot include source context if no source + // available + int[] lineStartEnd = getLineStartEnd(this.startPosition); + s.append(this.sourceCode.substring(lineStartEnd[0], lineStartEnd[1])) + .append("\n"); int col = lineStartEnd[0]; // When inserting the whitespace, ensure tabs in the source line are respected - while ((col) < startPosition) { - s.append(sourceCode.charAt(col++)=='\t'?"\t":" "); + while ((col) < this.startPosition) { + s.append(this.sourceCode.charAt(col++) == '\t' ? "\t" : " "); } // Want at least one ^ s.append("^"); col++; - while ((col++) < endPosition) { + while ((col++) < this.endPosition) { s.append("^"); } s.append("\n"); } - s.append(kind).append(":").append(message).append("\n"); + s.append(this.kind).append(":").append(this.message).append("\n"); s.append("==========\n"); return s.toString(); } /** - * For a given position in the source code this method returns a pair of int - * that indicate the start and end of the line within the source code that - * contain the position. - * + * For a given position in the source code this method returns a pair of int that + * indicate the start and end of the line within the source code that contain the + * position. * @param searchPos the position of interest in the source code * @return an int array of length 2 containing the start and end positions of the line */ @@ -115,13 +117,20 @@ public class CompilationMessage { int previousPos = -1; int pos = 0; do { - pos = sourceCode.indexOf('\n', previousPos + 1); + pos = this.sourceCode.indexOf('\n', previousPos + 1); if (searchPos < pos) { return new int[] { previousPos + 1, pos }; } previousPos = pos; - } while (pos != -1); - return new int[] { previousPos + 1, sourceCode.length() }; + } + while (pos != -1); + return new int[] { previousPos + 1, this.sourceCode.length() }; + } + + enum Kind { + + ERROR, OTHER + } // TODO test coverage for first line/last line situations diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationOutputCollector.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationOutputCollector.java index 6b8398a22..d886de9e6 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationOutputCollector.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationOutputCollector.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -24,10 +24,11 @@ import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject.Kind; /** - * During compilation instances of this class will collect up the output files from the compilation process. - * Any kind of file is collected upon but access is only currently provided to retrieve classes produced - * during compilation. Annotation processors that run may create other kinds of artifact. - * + * During compilation instances of this class will collect up the output files from the + * compilation process. Any kind of file is collected upon but access is only currently + * provided to retrieve classes produced during compilation. Annotation processors that + * run may create other kinds of artifact. + * * @author Andy Clement */ public class CompilationOutputCollector { @@ -35,35 +36,37 @@ public class CompilationOutputCollector { private List outputFiles = new ArrayList<>(); /** - * Retrieve compiled classes that have been collected since this collector - * was built. Due to annotation processing it is possible other source files - * or metadata files may be produced during compilation - those are not included - * in the returned list. - * + * Retrieve compiled classes that have been collected since this collector was built. + * Due to annotation processing it is possible other source files or metadata files + * may be produced during compilation - those are not included in the returned list. * @return list of compiled classes */ public List getCompiledClasses() { List compiledClassDefinitions = new ArrayList<>(); - for (InMemoryJavaFileObject outputFile : outputFiles) { + for (InMemoryJavaFileObject outputFile : this.outputFiles) { if (outputFile.getKind() == Kind.CLASS) { - CompiledClassDefinition compiledClassDefinition = new CompiledClassDefinition(outputFile.getName(), - outputFile.getBytes()); + CompiledClassDefinition compiledClassDefinition = new CompiledClassDefinition( + outputFile.getName(), outputFile.getBytes()); compiledClassDefinitions.add(compiledClassDefinition); } } return compiledClassDefinitions; } - public InMemoryJavaFileObject getJavaFileForOutput(Location location, String className, Kind kind, FileObject sibling) { - InMemoryJavaFileObject jfo = InMemoryJavaFileObject.getJavaFileObject(location, className, kind, sibling); - outputFiles.add(jfo); + public InMemoryJavaFileObject getJavaFileForOutput(Location location, + String className, Kind kind, FileObject sibling) { + InMemoryJavaFileObject jfo = InMemoryJavaFileObject.getJavaFileObject(location, + className, kind, sibling); + this.outputFiles.add(jfo); return jfo; } - public InMemoryJavaFileObject getFileForOutput(Location location, String packageName, String relativeName, FileObject sibling) { - InMemoryJavaFileObject ojfo = InMemoryJavaFileObject.getFileObject(location, packageName, relativeName, sibling); - outputFiles.add(ojfo); + public InMemoryJavaFileObject getFileForOutput(Location location, String packageName, + String relativeName, FileObject sibling) { + InMemoryJavaFileObject ojfo = InMemoryJavaFileObject.getFileObject(location, + packageName, relativeName, sibling); + this.outputFiles.add(ojfo); return ojfo; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationResult.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationResult.java index 829cda196..a686955db 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationResult.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompilationResult.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -24,25 +24,24 @@ import java.util.List; import java.util.Map; /** - * Holder for the results of compilation. If compilation was successful the set - * of classes that resulted from compilation will be available. If compilation - * was not successful the error messages should provide information about why. - * Note that compilation may succeed and yet there will still be informational or - * warning messages collected. - * + * Holder for the results of compilation. If compilation was successful the set of classes + * that resulted from compilation will be available. If compilation was not successful the + * error messages should provide information about why. Note that compilation may succeed + * and yet there will still be informational or warning messages collected. + * * @author Andy Clement * @author Mark Fisher */ public class CompilationResult { - private boolean successfulCompilation; - List compilationMessages = new ArrayList<>(); List> compiledClasses = new ArrayList<>(); + private boolean successfulCompilation; + private Map classBytes = new HashMap<>(); - + private List resolvedAdditionalDependencies = new ArrayList<>(); public CompilationResult(boolean successfulCompilation) { @@ -52,29 +51,34 @@ public class CompilationResult { public void addClassBytes(String name, byte[] bytes) { this.classBytes.put(name, bytes); } - - public void setResolvedAdditionalDependencies(List resolvedAdditionalDependencies) { - this.resolvedAdditionalDependencies = resolvedAdditionalDependencies; - } - + public List getResolvedAdditionalDependencies() { return this.resolvedAdditionalDependencies; } + public void setResolvedAdditionalDependencies( + List resolvedAdditionalDependencies) { + this.resolvedAdditionalDependencies = resolvedAdditionalDependencies; + } + public byte[] getClassBytes(String classname) { return this.classBytes.get(classname); } public boolean wasSuccessful() { - return successfulCompilation; + return this.successfulCompilation; } public List> getCompiledClasses() { - return compiledClasses; + return this.compiledClasses; } - + + public void setCompiledClasses(List> compiledClasses) { + this.compiledClasses = compiledClasses; + } + public List getCompilationMessages() { - return Collections.unmodifiableList(compilationMessages); + return Collections.unmodifiableList(this.compilationMessages); } public void recordCompilationMessage(CompilationMessage message) { @@ -85,15 +89,12 @@ public class CompilationResult { this.compilationMessages.addAll(messages); } - public void setCompiledClasses(List> compiledClasses) { - this.compiledClasses = compiledClasses; - } - public String toString() { StringBuilder s = new StringBuilder(); - s.append("Compilation result: #classes="+compiledClasses.size()+" #messages="+compilationMessages.size()+"\n"); - s.append("Compiled classes:\n").append(compiledClasses).append("\n"); - s.append("Compilation messages:\n").append(compilationMessages).append("\n"); + s.append("Compilation result: #classes=" + this.compiledClasses.size() + + " #messages=" + this.compilationMessages.size() + "\n"); + s.append("Compiled classes:\n").append(this.compiledClasses).append("\n"); + s.append("Compilation messages:\n").append(this.compilationMessages).append("\n"); return s.toString(); } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompiledClassDefinition.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompiledClassDefinition.java index 4dbbeb972..00e54e307 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompiledClassDefinition.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompiledClassDefinition.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2012-2019 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. @@ -24,25 +24,30 @@ package org.springframework.cloud.function.compiler.java; public class CompiledClassDefinition { private byte[] bytes; + private String filename; + private String classname; public CompiledClassDefinition(String filename, byte[] bytes) { this.filename = filename; this.bytes = bytes; this.classname = filename; - if (classname.startsWith("/")) { - classname = classname.substring(1); + if (this.classname.startsWith("/")) { + this.classname = this.classname.substring(1); } - classname = classname.replace('/', '.').substring(0, classname.length() - 6); // strip off .class + this.classname = this.classname.replace('/', '.').substring(0, + this.classname.length() - 6); // strip + // off + // .class } public String getName() { - return filename; + return this.filename; } public byte[] getBytes() { - return bytes; + return this.bytes; } @Override diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompositeProxySelector.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompositeProxySelector.java index 7e0b5d147..1a3df53ac 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompositeProxySelector.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/CompositeProxySelector.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DependencyResolver.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DependencyResolver.java index c5a5f87ba..0592927a7 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DependencyResolver.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DependencyResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -36,7 +36,6 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.name.Named; import com.google.inject.name.Names; - import org.apache.maven.artifact.repository.ArtifactRepository; import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; import org.apache.maven.artifact.repository.MavenArtifactRepository; @@ -98,24 +97,32 @@ import org.eclipse.sisu.plexus.ClassRealmManager; import org.springframework.core.io.Resource; import org.springframework.util.StringUtils; -public class DependencyResolver { +/** + * Dependency resolver utility class. + * + * @author Andy Clement + */ +public final class DependencyResolver { private static DependencyResolver instance = new DependencyResolver(); private static Properties globals; + private final Object lock = new Object(); + private LocalRepositoryManagerFactory localRepositoryManagerFactory; private PlexusContainer container; - private final Object lock = new Object(); - private ProjectBuilder projectBuilder; private RepositorySystem repositorySystem; private MavenSettings settings; + private DependencyResolver() { + } + public static DependencyResolver instance() { return instance; } @@ -124,12 +131,13 @@ public class DependencyResolver { instance = new DependencyResolver(); } - private DependencyResolver() { + static Properties getGlobals() { + return globals; } private void initialize() { if (this.container == null) { - synchronized (lock) { + synchronized (this.lock) { if (this.container == null) { ClassWorld classWorld = new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader()); @@ -142,14 +150,14 @@ public class DependencyResolver { try { container = new DefaultPlexusContainer(config, new AetherModule(), new DependencyResolutionModule()); - localRepositoryManagerFactory = container + this.localRepositoryManagerFactory = container .lookup(LocalRepositoryManagerFactory.class); container.addComponent( new ClassRealmManager((MutablePlexusContainer) container, new DefaultBeanLocator()), ClassRealmManager.class.getName()); - projectBuilder = container.lookup(ProjectBuilder.class); - repositorySystem = container.lookup(RepositorySystem.class); + this.projectBuilder = container.lookup(ProjectBuilder.class); + this.repositorySystem = container.lookup(RepositorySystem.class); } catch (Exception e) { throw new IllegalStateException("Cannot create container", e); @@ -172,7 +180,7 @@ public class DependencyResolver { ProjectBuildingRequest request = getProjectBuildingRequest(properties); request.setResolveDependencies(true); synchronized (DependencyResolver.class) { - ProjectBuildingResult result = projectBuilder + ProjectBuildingResult result = this.projectBuilder .build(new PropertiesModelSource(properties, resource), request); DependencyResolver.globals = null; DependencyResolutionResult dependencies = result @@ -224,7 +232,7 @@ public class DependencyResolver { projectBuildingRequest.setRepositoryMerging(RepositoryMerging.REQUEST_DOMINANT); projectBuildingRequest.setRemoteRepositories(mavenRepositories(properties)); projectBuildingRequest.getRemoteRepositories() - .addAll(mavenRepositories(settings)); + .addAll(mavenRepositories(this.settings)); projectBuildingRequest.setRepositorySession(session); projectBuildingRequest.setProcessPlugins(false); projectBuildingRequest.setBuildStartTime(new Date()); @@ -250,8 +258,10 @@ public class DependencyResolver { private List mavenRepositories(Properties properties) { List list = new ArrayList<>(); - addRepositoryIfMissing(list, "spring-snapshots", "https://repo.spring.io/libs-snapshot", true, true); - addRepositoryIfMissing(list, "central", "https://repo1.maven.org/maven2", true, false); + addRepositoryIfMissing(list, "spring-snapshots", + "https://repo.spring.io/libs-snapshot", true, true); + addRepositoryIfMissing(list, "central", "https://repo1.maven.org/maven2", true, + false); return list; } @@ -309,7 +319,7 @@ public class DependencyResolver { DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession(); LocalRepository repository = localRepository(properties); session.setLocalRepositoryManager( - localRepositoryManagerFactory.newInstance(session, repository)); + this.localRepositoryManagerFactory.newInstance(session, repository)); applySettings(session); ProxySelector existing = session.getProxySelector(); if (existing == null || !(existing instanceof CompositeProxySelector)) { @@ -322,7 +332,7 @@ public class DependencyResolver { } private void applySettings(DefaultRepositorySystemSession session) { - MavenSettingsReader.applySettings(settings, session); + MavenSettingsReader.applySettings(this.settings, session); } private LocalRepository localRepository(Properties properties) { @@ -338,7 +348,7 @@ public class DependencyResolver { try { ProjectBuildingRequest request = getProjectBuildingRequest(properties); request.setResolveDependencies(false); - ProjectBuildingResult result = projectBuilder + ProjectBuildingResult result = this.projectBuilder .build(new PropertiesModelSource(properties, resource), request); return result.getProject().getModel(); } @@ -383,13 +393,10 @@ public class DependencyResolver { return list; } - static Properties getGlobals() { - return globals; - } - @SuppressWarnings("deprecation") private static final class PropertiesModelSource implements org.apache.maven.model.building.ModelSource { + private final Properties properties; private final Resource resource; @@ -401,8 +408,8 @@ public class DependencyResolver { @Override public InputStream getInputStream() throws IOException { - DependencyResolver.globals = properties; - return new BufferedInputStream(resource.getInputStream()) { + DependencyResolver.globals = this.properties; + return new BufferedInputStream(this.resource.getInputStream()) { @Override public void close() throws IOException { DependencyResolver.globals = null; @@ -413,8 +420,9 @@ public class DependencyResolver { @Override public String getLocation() { - return resource.getDescription(); + return this.resource.getDescription(); } + } } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEntryJavaFileObject.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEntryJavaFileObject.java index 949927778..c18ecbd9c 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEntryJavaFileObject.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEntryJavaFileObject.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -31,12 +31,13 @@ import javax.tools.JavaFileObject; /** * A JavaFileObject that represents a file in a directory. - * + * * @author Andy Clement */ public class DirEntryJavaFileObject implements JavaFileObject { private File file; + private File basedir; public DirEntryJavaFileObject(File basedir, File file) { @@ -46,22 +47,23 @@ public class DirEntryJavaFileObject implements JavaFileObject { @Override public URI toUri() { - return file.toURI(); + return this.file.toURI(); } /** - * @return the path of the file relative to the base directory, for example: a/b/c/D.class + * @return the path of the file relative to the base directory, for example: + * a/b/c/D.class */ @Override public String getName() { - String basedirPath = basedir.getPath(); - String filePath = file.getPath(); - return filePath.substring(basedirPath.length()+1); + String basedirPath = this.basedir.getPath(); + String filePath = this.file.getPath(); + return filePath.substring(basedirPath.length() + 1); } @Override public InputStream openInputStream() throws IOException { - return new FileInputStream(file); + return new FileInputStream(this.file); } @Override @@ -72,13 +74,15 @@ public class DirEntryJavaFileObject implements JavaFileObject { @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("openReader() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "openReader() not supported on class file: " + getName()); } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("getCharContent() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "getCharContent() not supported on class file: " + getName()); } @Override @@ -88,7 +92,7 @@ public class DirEntryJavaFileObject implements JavaFileObject { @Override public long getLastModified() { - return file.lastModified(); + return this.file.lastModified(); } @Override @@ -123,16 +127,17 @@ public class DirEntryJavaFileObject implements JavaFileObject { @Override public int hashCode() { - return file.getName().hashCode()*37+basedir.getName().hashCode(); + return this.file.getName().hashCode() * 37 + this.basedir.getName().hashCode(); } - + @Override public boolean equals(Object obj) { if (!(obj instanceof DirEntryJavaFileObject)) { return false; } - DirEntryJavaFileObject that = (DirEntryJavaFileObject)obj; - return (basedir.getName().equals(that.basedir.getName())) && (file.getName().equals(that.file.getName())); + DirEntryJavaFileObject that = (DirEntryJavaFileObject) obj; + return (this.basedir.getName().equals(that.basedir.getName())) + && (this.file.getName().equals(that.file.getName())); } - -} \ No newline at end of file + +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEnumeration.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEnumeration.java index c7df9be18..427815f22 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEnumeration.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/DirEnumeration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2012-2019 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. @@ -43,15 +43,16 @@ public class DirEnumeration implements Enumeration { } private void computeValue() { - if (filesToReturn == null) { // Indicates we haven't started yet - filesToReturn = new ArrayList<>(); - directoriesToExplore = new ArrayList<>(); - visitDirectory(basedir); + if (this.filesToReturn == null) { // Indicates we haven't started yet + this.filesToReturn = new ArrayList<>(); + this.directoriesToExplore = new ArrayList<>(); + visitDirectory(this.basedir); } - if (filesToReturn.size() == 0) { - while (filesToReturn.size() == 0 && directoriesToExplore.size() != 0) { - File nextDir = directoriesToExplore.get(0); - directoriesToExplore.remove(0); + if (this.filesToReturn.size() == 0) { + while (this.filesToReturn.size() == 0 + && this.directoriesToExplore.size() != 0) { + File nextDir = this.directoriesToExplore.get(0); + this.directoriesToExplore.remove(0); visitDirectory(nextDir); } } @@ -60,50 +61,52 @@ public class DirEnumeration implements Enumeration { @Override public boolean hasMoreElements() { computeValue(); - return filesToReturn.size() != 0; + return this.filesToReturn.size() != 0; } @Override public File nextElement() { computeValue(); - if (filesToReturn.size()==0) { + if (this.filesToReturn.size() == 0) { throw new NoSuchElementException(); } - File toReturn = filesToReturn.get(0); - filesToReturn.remove(0); + File toReturn = this.filesToReturn.get(0); + this.filesToReturn.remove(0); return toReturn; } private void visitDirectory(File dir) { File[] files = dir.listFiles(); if (files != null) { - for (File file: files) { + for (File file : files) { if (file.isDirectory()) { - directoriesToExplore.add(file); - } else { - filesToReturn.add(file); + this.directoriesToExplore.add(file); + } + else { + this.filesToReturn.add(file); } } } } public File getDirectory() { - return basedir; + return this.basedir; } /** - * Return the relative path of this file to the base directory that the directory enumeration was - * started for. + * Return the relative path of this file to the base directory that the directory + * enumeration was started for. * @param file a file discovered returned by this enumeration * @return the relative path of the file (for example: a/b/c/D.class) */ public String getName(File file) { - String basedirPath = basedir.getPath(); + String basedirPath = this.basedir.getPath(); String filePath = file.getPath(); if (!filePath.startsWith(basedirPath)) { - throw new IllegalStateException("The file '"+filePath+"' is not nested below the base directory '"+basedirPath+"'"); + throw new IllegalStateException("The file '" + filePath + + "' is not nested below the base directory '" + basedirPath + "'"); } - return filePath.substring(basedirPath.length()+1); + return filePath.substring(basedirPath.length() + 1); } } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/InMemoryJavaFileObject.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/InMemoryJavaFileObject.java index ef012dac0..73f24cc97 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/InMemoryJavaFileObject.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/InMemoryJavaFileObject.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -42,30 +42,40 @@ import org.slf4j.LoggerFactory; /** * A JavaFileObject that represents a source artifact created for compilation or an output - * artifact producing during compilation (a .class file or some other thing if an annotation - * processor has run). In order to be clear what it is being used for there are static factory - * methods that ask for specific types of file. - * + * artifact producing during compilation (a .class file or some other thing if an + * annotation processor has run). In order to be clear what it is being used for there are + * static factory methods that ask for specific types of file. + * * @author Andy Clement */ -public class InMemoryJavaFileObject implements JavaFileObject { +public final class InMemoryJavaFileObject implements JavaFileObject { + + private final static Logger logger = LoggerFactory + .getLogger(InMemoryJavaFileObject.class); - private final static Logger logger = LoggerFactory.getLogger(InMemoryJavaFileObject.class); - private Location location; + private String packageName; + private String relativeName; + private FileObject sibling; + private String className; + private Kind kind; - + private byte[] content = null; + private long lastModifiedTime = 0; + private URI uri = null; - - private InMemoryJavaFileObject() {} - - public static InMemoryJavaFileObject getFileObject(Location location, String packageName, String relativeName, FileObject sibling) { + + private InMemoryJavaFileObject() { + } + + public static InMemoryJavaFileObject getFileObject(Location location, + String packageName, String relativeName, FileObject sibling) { InMemoryJavaFileObject retval = new InMemoryJavaFileObject(); retval.kind = Kind.OTHER; retval.location = location; @@ -74,8 +84,9 @@ public class InMemoryJavaFileObject implements JavaFileObject { retval.sibling = sibling; return retval; } - - public static InMemoryJavaFileObject getJavaFileObject(Location location, String className, Kind kind, FileObject sibling) { + + public static InMemoryJavaFileObject getJavaFileObject(Location location, + String className, Kind kind, FileObject sibling) { InMemoryJavaFileObject retval = new InMemoryJavaFileObject(); retval.location = location; retval.className = className; @@ -84,7 +95,8 @@ public class InMemoryJavaFileObject implements JavaFileObject { return retval; } - public static InMemoryJavaFileObject getSourceJavaFileObject(String className, String content) { + public static InMemoryJavaFileObject getSourceJavaFileObject(String className, + String content) { InMemoryJavaFileObject retval = new InMemoryJavaFileObject(); retval.location = StandardLocation.SOURCE_PATH; retval.className = className; @@ -92,37 +104,46 @@ public class InMemoryJavaFileObject implements JavaFileObject { retval.content = content.getBytes(); return retval; } - + public byte[] getBytes() { - return content; + return this.content; } public String toString() { - return "OutputJavaFileObject: Location="+location+",className="+className+",kind="+kind+",relativeName="+relativeName+",sibling="+sibling+",packageName="+packageName; + return "OutputJavaFileObject: Location=" + this.location + ",className=" + + this.className + ",kind=" + this.kind + ",relativeName=" + + this.relativeName + ",sibling=" + this.sibling + ",packageName=" + + this.packageName; } - + @Override public URI toUri() { - // These memory based output files 'pretend' to be relative to the file system root - if (uri == null) { + // These memory based output files 'pretend' to be relative to the file system + // root + if (this.uri == null) { String name = null; - if (className != null) { - name = className.replace('.', '/'); - } else if (packageName !=null && packageName.length()!=0) { - name = packageName.replace('.', '/')+'/'+relativeName; - } else { - name = relativeName; + if (this.className != null) { + name = this.className.replace('.', '/'); } - + else if (this.packageName != null && this.packageName.length() != 0) { + name = this.packageName.replace('.', '/') + '/' + this.relativeName; + } + else { + name = this.relativeName; + } + String uriString = null; try { - uriString = "file:/"+name+kind.extension; - uri = new URI(uriString); - } catch (URISyntaxException e) { - throw new IllegalStateException("Unexpected URISyntaxException for string '" + uriString + "'", e); + uriString = "file:/" + name + this.kind.extension; + this.uri = new URI(uriString); + } + catch (URISyntaxException e) { + throw new IllegalStateException( + "Unexpected URISyntaxException for string '" + uriString + "'", + e); } } - return uri; + return this.uri; } @Override @@ -132,22 +153,22 @@ public class InMemoryJavaFileObject implements JavaFileObject { @Override public InputStream openInputStream() throws IOException { - if (content == null) { + if (this.content == null) { throw new FileNotFoundException(); } - logger.debug("opening input stream for {}",getName()); - return new ByteArrayInputStream(content); + logger.debug("opening input stream for {}", getName()); + return new ByteArrayInputStream(this.content); } @Override public OutputStream openOutputStream() throws IOException { - logger.debug("opening output stream for {}",getName()); + logger.debug("opening output stream for {}", getName()); return new ByteArrayOutputStream() { @Override public void close() throws IOException { super.close(); - lastModifiedTime = System.currentTimeMillis(); - content = this.toByteArray(); + InMemoryJavaFileObject.this.lastModifiedTime = System.currentTimeMillis(); + InMemoryJavaFileObject.this.content = this.toByteArray(); } }; } @@ -159,31 +180,34 @@ public class InMemoryJavaFileObject implements JavaFileObject { @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { - if (kind!=Kind.SOURCE) { - throw new UnsupportedOperationException("getCharContent() not supported on file object: " + getName()); + if (this.kind != Kind.SOURCE) { + throw new UnsupportedOperationException( + "getCharContent() not supported on file object: " + getName()); } // Not yet supporting encodings - return (content==null?null:new String(content)); + return (this.content == null ? null : new String(this.content)); } @Override public Writer openWriter() throws IOException { // Let's not enforce this restriction right now -// if (kind == Kind.CLASS) { -// throw new UnsupportedOperationException("openWriter() not supported on file object: " + getName()); -// } + // if (kind == Kind.CLASS) { + // throw new UnsupportedOperationException("openWriter() not supported on file + // object: " + getName()); + // } return new CharArrayWriter() { @Override public void close() { - lastModifiedTime = System.currentTimeMillis(); - content = new String(toCharArray()).getBytes(); // Ignoring encoding... + InMemoryJavaFileObject.this.lastModifiedTime = System.currentTimeMillis(); + InMemoryJavaFileObject.this.content = new String(toCharArray()) + .getBytes(); // Ignoring encoding... }; }; } @Override public long getLastModified() { - return lastModifiedTime; + return this.lastModifiedTime; } @Override @@ -193,15 +217,14 @@ public class InMemoryJavaFileObject implements JavaFileObject { @Override public Kind getKind() { - return kind; + return this.kind; } public boolean isNameCompatible(String simpleName, Kind kind) { - String baseName = simpleName + kind.extension; - return kind.equals(getKind()) - && (baseName.equals(toUri().getPath()) - || toUri().getPath().endsWith("/" + baseName)); - } + String baseName = simpleName + kind.extension; + return kind.equals(getKind()) && (baseName.equals(toUri().getPath()) + || toUri().getPath().endsWith("/" + baseName)); + } @Override public NestingKind getNestingKind() { @@ -212,5 +235,5 @@ public class InMemoryJavaFileObject implements JavaFileObject { public Modifier getAccessLevel() { return null; } - -} \ No newline at end of file + +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableClasspath.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableClasspath.java index bfad28718..13757033e 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableClasspath.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableClasspath.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2012-2019 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. @@ -33,14 +33,14 @@ import javax.tools.JavaFileObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager.CompilationInfoCache; import org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager.CompilationInfoCache.ArchiveInfo; /** - * Iterable that will produce an iterator that returns classes found - * on a specified classpath that meet specified criteria. For jars it finds, the - * iterator will go into nested jars - this handles the situation with a - * spring boot uberjar. + * Iterable that will produce an iterator that returns classes found on a specified + * classpath that meet specified criteria. For jars it finds, the iterator will go into + * nested jars - this handles the situation with a spring boot uberjar. * * @author Andy Clement */ @@ -55,10 +55,13 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable /** * @param compilationInfoCache cache of info that may help accelerate compilation * @param classpath a classpath of jars/directories - * @param packageNameFilter an optional package name if choosing to filter (e.g. com.example) - * @param includeSubpackages if true, include results in subpackages of the specified package filter + * @param packageNameFilter an optional package name if choosing to filter (e.g. + * com.example) + * @param includeSubpackages if true, include results in subpackages of the specified + * package filter */ - IterableClasspath(CompilationInfoCache compilationInfoCache, String classpath, String packageNameFilter, boolean includeSubpackages) { + IterableClasspath(CompilationInfoCache compilationInfoCache, String classpath, + String packageNameFilter, boolean includeSubpackages) { super(compilationInfoCache, packageNameFilter, includeSubpackages); StringTokenizer tokenizer = new StringTokenizer(classpath, File.pathSeparator); while (tokenizer.hasMoreElements()) { @@ -66,177 +69,230 @@ public class IterableClasspath extends CloseableFilterableJavaFileObjectIterable File f = new File(nextEntry); if (f.exists()) { // Skip iterating over archives that cannot possibly match the filter - if (this.packageNameFilter != null && this.packageNameFilter.length() > 0) { + if (this.packageNameFilter != null + && this.packageNameFilter.length() > 0) { ArchiveInfo archiveInfo = compilationInfoCache.getArchiveInfoFor(f); - if (archiveInfo != null && !archiveInfo.containsPackage(this.packageNameFilter, this.includeSubpackages)) { + if (archiveInfo != null + && !archiveInfo.containsPackage(this.packageNameFilter, + this.includeSubpackages)) { continue; } } - classpathEntries.add(f); - } else { - logger.debug("path element does not exist {}",f); + this.classpathEntries.add(f); + } + else { + logger.debug("path element does not exist {}", f); } } } public void close() { - for (ZipFile openArchive : openArchives) { + for (ZipFile openArchive : this.openArchives) { try { openArchive.close(); - } catch (IOException ioe) { - logger.debug("Unexpected error closing archive {}",openArchive,ioe); + } + catch (IOException ioe) { + logger.debug("Unexpected error closing archive {}", openArchive, ioe); } } - openArchives.clear(); + this.openArchives.clear(); } public Iterator iterator() { return new ClasspathEntriesIterator(); } - class ClasspathEntriesIterator implements Iterator { - private int currentClasspathEntriesIndex = 0; - - // Walking one of three possible things: directory tree, zip, or Java runtime packaged in JDK9+ form - private File openDirectory = null; - private DirEnumeration openDirectoryEnumeration = null; - - private ZipFile openArchive = null; - private File openFile = null; - private ZipEntry nestedZip = null; - private Stack> openArchiveEnumeration = null; - - private File openJrt; - private JrtFsEnumeration openJrtEnumeration = null; - - private JavaFileObject nextEntry = null; - - private void findNext() { - if (nextEntry == null) { - try { - while (openArchive!=null || openDirectory!=null || openJrt != null || currentClasspathEntriesIndex < classpathEntries.size()) { - if (openArchive == null && openDirectory == null && openJrt == null) { - // Open the next item - File nextFile = classpathEntries.get(currentClasspathEntriesIndex); - if (nextFile.isDirectory()) { - openDirectory = nextFile; - openDirectoryEnumeration = new DirEnumeration(nextFile); - } else if (nextFile.getName().endsWith("jrt-fs.jar")) { - openJrt = nextFile; - openJrtEnumeration = new JrtFsEnumeration(nextFile,null); - } else { - openFile = nextFile; - openArchive = new ZipFile(nextFile); - openArchives.add(openArchive); - openArchiveEnumeration = new Stack>(); - openArchiveEnumeration.push(openArchive.entries()); - } - currentClasspathEntriesIndex++; - } - if (openArchiveEnumeration != null) { - while (!openArchiveEnumeration.isEmpty()) { - while (openArchiveEnumeration.peek().hasMoreElements()) { - ZipEntry entry = openArchiveEnumeration.peek().nextElement(); - String entryName = entry.getName(); - if (accept(entryName)) { - if (nestedZip!=null) { - nextEntry = new NestedZipEntryJavaFileObject(openFile, openArchive,nestedZip, entry); - } else { - nextEntry = new ZipEntryJavaFileObject(openFile, openArchive, entry); - } - return; - } else if (nestedZip == null && entryName.startsWith(MemoryBasedJavaFileManager.BOOT_PACKAGING_PREFIX_FOR_LIBRARIES) && entryName.endsWith(".jar")) { - // nested jar in uber jar - logger.debug("opening nested archive {}",entry.getName()); - ZipInputStream zis = new ZipInputStream(openArchive.getInputStream(entry)); - Enumeration nestedZipEnumerator = new ZipEnumerator(zis); - nestedZip = entry; - openArchiveEnumeration.push(nestedZipEnumerator); - } - } - openArchiveEnumeration.pop(); - if (nestedZip ==null) { openArchive = null; openFile = null; } - else nestedZip = null; - } - openArchiveEnumeration = null; - openArchive = null; - openFile = null; - } else if (openDirectoryEnumeration != null) { - while (openDirectoryEnumeration.hasMoreElements()) { - File entry = openDirectoryEnumeration.nextElement(); - String name = openDirectoryEnumeration.getName(entry); - if (accept(name)) { - nextEntry = new DirEntryJavaFileObject(openDirectoryEnumeration.getDirectory(), entry); - return; - } - } - openDirectoryEnumeration = null; - openDirectory = null; - } else if (openJrtEnumeration != null) { - while (openJrtEnumeration.hasMoreElements()) { - JrtEntryJavaFileObject jrtEntry = openJrtEnumeration.nextElement(); - String name = openJrtEnumeration.getName(jrtEntry); - if (accept(name)) { - nextEntry = jrtEntry; - return; - } - } - openJrtEnumeration = null; - openJrt = null; - } - } - } catch (IOException ioe) { - logger.debug("Unexpected error whilst processing classpath entries",ioe); - } - } - } - - public boolean hasNext() { - findNext(); - return nextEntry != null; - } - - public JavaFileObject next() { - findNext(); - if (nextEntry == null) { - throw new NoSuchElementException(); - } - JavaFileObject retval = nextEntry; - nextEntry = null; - return retval; - } - + public void reset() { + close(); } - static class ZipEnumerator implements Enumeration{ + static class ZipEnumerator implements Enumeration { private ZipInputStream zis; + private ZipEntry nextEntry = null; - public ZipEnumerator(ZipInputStream zis) { + ZipEnumerator(ZipInputStream zis) { this.zis = zis; } @Override public boolean hasMoreElements() { try { - nextEntry = zis.getNextEntry(); - } catch (IOException ioe) { - nextEntry=null; + this.nextEntry = this.zis.getNextEntry(); } - return nextEntry!=null; + catch (IOException ioe) { + this.nextEntry = null; + } + return this.nextEntry != null; } @Override public ZipEntry nextElement() { - ZipEntry retval = nextEntry; - nextEntry = null; + ZipEntry retval = this.nextEntry; + this.nextEntry = null; return retval; } } - public void reset() { - close(); + class ClasspathEntriesIterator implements Iterator { + + private int currentClasspathEntriesIndex = 0; + + // Walking one of three possible things: directory tree, zip, or Java runtime + // packaged in JDK9+ form + private File openDirectory = null; + + private DirEnumeration openDirectoryEnumeration = null; + + private ZipFile openArchive = null; + + private File openFile = null; + + private ZipEntry nestedZip = null; + + private Stack> openArchiveEnumeration = null; + + private File openJrt; + + private JrtFsEnumeration openJrtEnumeration = null; + + private JavaFileObject nextEntry = null; + + private void findNext() { + if (this.nextEntry == null) { + try { + while (this.openArchive != null || this.openDirectory != null + || this.openJrt != null + || this.currentClasspathEntriesIndex < IterableClasspath.this.classpathEntries + .size()) { + if (this.openArchive == null && this.openDirectory == null + && this.openJrt == null) { + // Open the next item + File nextFile = IterableClasspath.this.classpathEntries + .get(this.currentClasspathEntriesIndex); + if (nextFile.isDirectory()) { + this.openDirectory = nextFile; + this.openDirectoryEnumeration = new DirEnumeration( + nextFile); + } + else if (nextFile.getName().endsWith("jrt-fs.jar")) { + this.openJrt = nextFile; + this.openJrtEnumeration = new JrtFsEnumeration(nextFile, + null); + } + else { + this.openFile = nextFile; + this.openArchive = new ZipFile(nextFile); + IterableClasspath.this.openArchives.add(this.openArchive); + this.openArchiveEnumeration = new Stack>(); + this.openArchiveEnumeration + .push(this.openArchive.entries()); + } + this.currentClasspathEntriesIndex++; + } + if (this.openArchiveEnumeration != null) { + while (!this.openArchiveEnumeration.isEmpty()) { + while (this.openArchiveEnumeration.peek() + .hasMoreElements()) { + ZipEntry entry = this.openArchiveEnumeration.peek() + .nextElement(); + String entryName = entry.getName(); + if (accept(entryName)) { + if (this.nestedZip != null) { + this.nextEntry = new NestedZipEntryJavaFileObject( + this.openFile, this.openArchive, + this.nestedZip, entry); + } + else { + this.nextEntry = new ZipEntryJavaFileObject( + this.openFile, this.openArchive, + entry); + } + return; + } + else if (this.nestedZip == null + && entryName.startsWith( + MemoryBasedJavaFileManager.BOOT_PACKAGING_PREFIX_FOR_LIBRARIES) + && entryName.endsWith(".jar")) { + // nested jar in uber jar + logger.debug("opening nested archive {}", + entry.getName()); + ZipInputStream zis = new ZipInputStream( + this.openArchive.getInputStream(entry)); + Enumeration nestedZipEnumerator = new ZipEnumerator( + zis); + this.nestedZip = entry; + this.openArchiveEnumeration + .push(nestedZipEnumerator); + } + } + this.openArchiveEnumeration.pop(); + if (this.nestedZip == null) { + this.openArchive = null; + this.openFile = null; + } + else { + this.nestedZip = null; + } + } + this.openArchiveEnumeration = null; + this.openArchive = null; + this.openFile = null; + } + else if (this.openDirectoryEnumeration != null) { + while (this.openDirectoryEnumeration.hasMoreElements()) { + File entry = this.openDirectoryEnumeration.nextElement(); + String name = this.openDirectoryEnumeration + .getName(entry); + if (accept(name)) { + this.nextEntry = new DirEntryJavaFileObject( + this.openDirectoryEnumeration.getDirectory(), + entry); + return; + } + } + this.openDirectoryEnumeration = null; + this.openDirectory = null; + } + else if (this.openJrtEnumeration != null) { + while (this.openJrtEnumeration.hasMoreElements()) { + JrtEntryJavaFileObject jrtEntry = this.openJrtEnumeration + .nextElement(); + String name = this.openJrtEnumeration.getName(jrtEntry); + if (accept(name)) { + this.nextEntry = jrtEntry; + return; + } + } + this.openJrtEnumeration = null; + this.openJrt = null; + } + } + } + catch (IOException ioe) { + logger.debug("Unexpected error whilst processing classpath entries", + ioe); + } + } + } + + public boolean hasNext() { + findNext(); + return this.nextEntry != null; + } + + public JavaFileObject next() { + findNext(); + if (this.nextEntry == null) { + throw new NoSuchElementException(); + } + JavaFileObject retval = this.nextEntry; + this.nextEntry = null; + return retval; + } + } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableJrtModule.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableJrtModule.java index 49174fb50..b6908d909 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableJrtModule.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/IterableJrtModule.java @@ -1,12 +1,12 @@ /* - * Copyright 2018 the original author or authors. - * + * Copyright 2012-2019 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. @@ -27,80 +27,42 @@ import javax.tools.JavaFileObject; import org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager.CompilationInfoCache; /** - * Iterable that will produce an iterator that returns classes found - * in a specific module tree within the Java runtime image that exists in - * Java 9 and later. - * + * Iterable that will produce an iterator that returns classes found in a specific module + * tree within the Java runtime image that exists in Java 9 and later. + * * @author Andy Clement */ public class IterableJrtModule extends CloseableFilterableJavaFileObjectIterable { -// private static Logger logger = LoggerFactory.getLogger(IterableJrtModule.class); + // private static Logger logger = LoggerFactory.getLogger(IterableJrtModule.class); + + Map walkers = new HashMap<>(); private Path moduleRootPath; - - Map walkers = new HashMap<>(); /** * @param compilationInfoCache cache of info that may help accelerate compilation * @param moduleRootPath path to the base of the relevant module within the JRT image - * @param packageNameFilter an optional package name if choosing to filter (e.g. com.example) - * @param includeSubpackages if true, include results in subpackages of the specified package filter + * @param packageNameFilter an optional package name if choosing to filter (e.g. + * com.example) + * @param includeSubpackages if true, include results in subpackages of the specified + * package filter */ - public IterableJrtModule(CompilationInfoCache compilationInfoCache, Path moduleRootPath, String packageNameFilter, - boolean includeSubpackages) { + public IterableJrtModule(CompilationInfoCache compilationInfoCache, + Path moduleRootPath, String packageNameFilter, boolean includeSubpackages) { super(compilationInfoCache, packageNameFilter, includeSubpackages); this.moduleRootPath = moduleRootPath; } public Iterator iterator() { - JrtFsEnumeration jrtFsWalker = walkers.get(moduleRootPath.toString()); + JrtFsEnumeration jrtFsWalker = this.walkers.get(this.moduleRootPath.toString()); if (jrtFsWalker == null) { - jrtFsWalker = new JrtFsEnumeration(null, moduleRootPath); - walkers.put(moduleRootPath.toString(), jrtFsWalker); + jrtFsWalker = new JrtFsEnumeration(null, this.moduleRootPath); + this.walkers.put(this.moduleRootPath.toString(), jrtFsWalker); } jrtFsWalker.reset(); return new IteratorOverJrtFsEnumeration(jrtFsWalker); } - - class IteratorOverJrtFsEnumeration implements Iterator { - - private JavaFileObject nextEntry = null; - - private JrtFsEnumeration jrtEnumeration; - - public IteratorOverJrtFsEnumeration(JrtFsEnumeration jrtFsWalker) { - this.jrtEnumeration = jrtFsWalker; - } - - private void findNext() { - if (nextEntry == null) { - while (jrtEnumeration.hasMoreElements()) { - JrtEntryJavaFileObject jrtEntry = jrtEnumeration.nextElement(); - String name = jrtEnumeration.getName(jrtEntry); - if (accept(name)) { - nextEntry = jrtEntry; - return; - } - } - } - } - - public boolean hasNext() { - findNext(); - return nextEntry != null; - } - - public JavaFileObject next() { - findNext(); - if (nextEntry == null) { - throw new NoSuchElementException(); - } - JavaFileObject retval = nextEntry; - nextEntry = null; - return retval; - } - } public void close() { } @@ -108,4 +70,45 @@ public class IterableJrtModule extends CloseableFilterableJavaFileObjectIterable public void reset() { close(); } -} \ No newline at end of file + + class IteratorOverJrtFsEnumeration implements Iterator { + + private JavaFileObject nextEntry = null; + + private JrtFsEnumeration jrtEnumeration; + + IteratorOverJrtFsEnumeration(JrtFsEnumeration jrtFsWalker) { + this.jrtEnumeration = jrtFsWalker; + } + + private void findNext() { + if (this.nextEntry == null) { + while (this.jrtEnumeration.hasMoreElements()) { + JrtEntryJavaFileObject jrtEntry = this.jrtEnumeration.nextElement(); + String name = this.jrtEnumeration.getName(jrtEntry); + if (accept(name)) { + this.nextEntry = jrtEntry; + return; + } + } + } + } + + public boolean hasNext() { + findNext(); + return this.nextEntry != null; + } + + public JavaFileObject next() { + findNext(); + if (this.nextEntry == null) { + throw new NoSuchElementException(); + } + JavaFileObject retval = this.nextEntry; + this.nextEntry = null; + return retval; + } + + } + +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtEntryJavaFileObject.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtEntryJavaFileObject.java index 99514b54a..519e5642f 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtEntryJavaFileObject.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtEntryJavaFileObject.java @@ -1,12 +1,12 @@ /* - * Copyright 2018 the original author or authors. - * + * Copyright 2012-2019 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. @@ -31,39 +31,44 @@ import javax.lang.model.element.NestingKind; import javax.tools.JavaFileObject; /** - * A JavaFileObject that represents a class from the Java runtime as packaged in Java 9 and later. - * + * A JavaFileObject that represents a class from the Java runtime as packaged in Java 9 + * and later. + * * @author Andy Clement */ public class JrtEntryJavaFileObject implements JavaFileObject { private String pathToClassString; + private Path path; /** - * @param path entry in the Java runtime filesystem, for example '/modules/java.base/java/lang/Object.class' + * @param path entry in the Java runtime filesystem, for example + * '/modules/java.base/java/lang/Object.class' */ public JrtEntryJavaFileObject(Path path) { - this.pathToClassString = path.subpath(2, path.getNameCount()).toString(); // e.g. java/lang/Object.class + this.pathToClassString = path.subpath(2, path.getNameCount()).toString(); // e.g. + // java/lang/Object.class this.path = path; } @Override public URI toUri() { - return path.toUri(); + return this.path.toUri(); } /** - * @return the path of the file relative to the base directory, for example: a/b/c/D.class + * @return the path of the file relative to the base directory, for example: + * a/b/c/D.class */ @Override public String getName() { - return pathToClassString; + return this.pathToClassString; } @Override public InputStream openInputStream() throws IOException { - byte[] bytes = Files.readAllBytes(path); + byte[] bytes = Files.readAllBytes(this.path); return new ByteArrayInputStream(bytes); } @@ -75,13 +80,15 @@ public class JrtEntryJavaFileObject implements JavaFileObject { @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("openReader() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "openReader() not supported on class file: " + getName()); } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("getCharContent() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "getCharContent() not supported on class file: " + getName()); } @Override @@ -92,9 +99,12 @@ public class JrtEntryJavaFileObject implements JavaFileObject { @Override public long getLastModified() { try { - return Files.getLastModifiedTime(path).toMillis(); - } catch (IOException ioe) { - throw new RuntimeException("Unable to determine last modified time of "+pathToClassString, ioe); + return Files.getLastModifiedTime(this.path).toMillis(); + } + catch (IOException ioe) { + throw new RuntimeException( + "Unable to determine last modified time of " + this.pathToClassString, + ioe); } } @@ -132,18 +142,18 @@ public class JrtEntryJavaFileObject implements JavaFileObject { public int hashCode() { return getName().hashCode(); } - + @Override public boolean equals(Object obj) { if (!(obj instanceof JrtEntryJavaFileObject)) { return false; } - JrtEntryJavaFileObject that = (JrtEntryJavaFileObject)obj; + JrtEntryJavaFileObject that = (JrtEntryJavaFileObject) obj; return (getName().equals(that.getName())); } public String getPathToClassString() { - return pathToClassString; + return this.pathToClassString; } - -} \ No newline at end of file + +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtFsEnumeration.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtFsEnumeration.java index 28dcf1634..4dc8b16eb 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtFsEnumeration.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/JrtFsEnumeration.java @@ -1,18 +1,19 @@ /* - * Copyright 2018 the original author or authors. - * + * Copyright 2012-2019 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 org.springframework.cloud.function.compiler.java; import java.io.File; @@ -31,25 +32,26 @@ import java.util.List; import java.util.NoSuchElementException; /** - * Walks a JrtFS treating it like a directory (to avoid overcomplicating the walking - * logic in IterableClasspath) - * + * Walks a JrtFS treating it like a directory (to avoid overcomplicating the walking logic + * in IterableClasspath). + * * @author Andy Clement */ public class JrtFsEnumeration implements Enumeration { - -// private final static Logger logger = LoggerFactory.getLogger(JrtFsEnumeration.class); + + // private final static Logger logger = + // LoggerFactory.getLogger(JrtFsEnumeration.class); private static URI JRT_URI = URI.create("jrt:/"); //$NON-NLS-1$ - + private final static FileSystem fs = FileSystems.getFileSystem(JRT_URI); - + private Path pathWithinJrt; - + private List jfos = new ArrayList<>(); - + private Integer counter = 0; - + private Boolean initialized = false; public JrtFsEnumeration(File jrtFsFile, Path pathWithinJrt) { @@ -57,72 +59,82 @@ public class JrtFsEnumeration implements Enumeration { ensureInitialized(); } - class FileCacheBuilderVisitor extends SimpleFileVisitor { - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - int fnc = file.getNameCount(); - if (fnc >= 3 && file.toString().endsWith(".class")) { // There is a preceeding module name - e.g. /modules/java.base/java/lang/Object.class - // file.subpath(2, fnc); // e.g. java/lang/Object.class - jfos.add(new JrtEntryJavaFileObject(file)); - } - return FileVisitResult.CONTINUE; - } - } - private void ensureInitialized() { - synchronized (initialized) { - if (initialized) { + synchronized (this.initialized) { + if (this.initialized) { return; } FileCacheBuilderVisitor visitor = new FileCacheBuilderVisitor(); - if (pathWithinJrt != null) { + if (this.pathWithinJrt != null) { try { - Files.walkFileTree(pathWithinJrt, visitor); - // System.out.println("JrtFs enumeration for '"+pathWithinJrt+"' with #"+jfos.size()+" entries"); - } catch (IOException e) { + Files.walkFileTree(this.pathWithinJrt, visitor); + // System.out.println("JrtFs enumeration for '"+pathWithinJrt+"' with + // #"+jfos.size()+" entries"); + } + catch (IOException e) { throw new RuntimeException(e); } - } else { + } + else { Iterable roots = fs.getRootDirectories(); try { for (java.nio.file.Path path : roots) { Files.walkFileTree(path, visitor); } - // System.out.println("JrtFs enumeration initialized with #"+jfos.size()+" entries"); - } catch (IOException e) { + // System.out.println("JrtFs enumeration initialized with + // #"+jfos.size()+" entries"); + } + catch (IOException e) { throw new RuntimeException(e); } } - initialized = true; + this.initialized = true; } } @Override public boolean hasMoreElements() { - return counter < jfos.size(); + return this.counter < this.jfos.size(); } @Override public JrtEntryJavaFileObject nextElement() { - if (counter>=jfos.size()) { + if (this.counter >= this.jfos.size()) { throw new NoSuchElementException(); } - JrtEntryJavaFileObject toReturn = jfos.get(counter++); + JrtEntryJavaFileObject toReturn = this.jfos.get(this.counter++); return toReturn; } /** - * Return the relative path of this file to the base directory that the directory enumeration was - * started for. - * @param file a file discovered returned by this enumeration + * Return the relative path of this file to the base directory that the directory + * enumeration was started for. + * @param file a file discovered returned by this enumeration * @return the relative path of the file (for example: a/b/c/D.class) */ public String getName(JrtEntryJavaFileObject file) { return file.getPathToClassString(); } - + public void reset() { - counter = 0; + this.counter = 0; + } + + class FileCacheBuilderVisitor extends SimpleFileVisitor { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + int fnc = file.getNameCount(); + if (fnc >= 3 && file.toString().endsWith(".class")) { // There is a preceeding + // module name - e.g. + // /modules/java.base/java/lang/Object.class + // file.subpath(2, fnc); // e.g. java/lang/Object.class + JrtFsEnumeration.this.jfos.add(new JrtEntryJavaFileObject(file)); + } + return FileVisitResult.CONTINUE; + } + } } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettings.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettings.java index 61a56d677..7b22f231e 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettings.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettings.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettingsReader.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettingsReader.java index fafeb14d3..de0426d92 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettingsReader.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MavenSettingsReader.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -58,17 +58,6 @@ public class MavenSettingsReader { this.homeDir = homeDir; } - public MavenSettings readSettings() { - Settings settings = loadSettings(); - SettingsDecryptionResult decrypted = decryptSettings(settings); - if (!decrypted.getProblems().isEmpty()) { - log.error( - "Maven settings decryption failed. Some Maven repositories may be inaccessible"); - // Continue - the encrypted credentials may not be used - } - return new MavenSettings(settings, decrypted); - } - public static void applySettings(MavenSettings settings, DefaultRepositorySystemSession session) { if (settings.getLocalRepository() != null) { @@ -89,6 +78,17 @@ public class MavenSettingsReader { session.setProxySelector(settings.getProxySelector()); } + public MavenSettings readSettings() { + Settings settings = loadSettings(); + SettingsDecryptionResult decrypted = decryptSettings(settings); + if (!decrypted.getProblems().isEmpty()) { + log.error( + "Maven settings decryption failed. Some Maven repositories may be inaccessible"); + // Continue - the encrypted credentials may not be used + } + return new MavenSettings(settings, decrypted); + } + private Settings loadSettings() { File settingsFile = new File(this.homeDir, ".m2/settings.xml"); if (settingsFile.exists()) { diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MemoryBasedJavaFileManager.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MemoryBasedJavaFileManager.java index 948f2bb81..2bcd2a23c 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MemoryBasedJavaFileManager.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/MemoryBasedJavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -55,6 +55,7 @@ import org.eclipse.aether.artifact.DefaultArtifact; import org.eclipse.aether.graph.Dependency; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + import org.springframework.cloud.function.compiler.java.IterableClasspath.ZipEnumerator; /** @@ -74,6 +75,10 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { private static Logger logger = LoggerFactory .getLogger(MemoryBasedJavaFileManager.class); + private static URI JRT_URI = URI.create("jrt:/"); + + private static FileSystem fs; + private CompilationOutputCollector outputCollector; private Map resolvedAdditionalDependencies = new LinkedHashMap<>(); @@ -86,9 +91,20 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { private Map iterables = new HashMap<>(); + private String jrtFsFilePath = null; + + private boolean checkedForJrtFsPath = false; + public MemoryBasedJavaFileManager() { - outputCollector = new CompilationOutputCollector(); - compilationInfoCache = new CompilationInfoCache(); + this.outputCollector = new CompilationOutputCollector(); + this.compilationInfoCache = new CompilationInfoCache(); + } + + private static FileSystem getJrtFs() { + if (fs == null) { + fs = FileSystems.getFileSystem(JRT_URI); + } + return fs; } @Override @@ -105,228 +121,14 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { return null; // Do not currently need to load plugins } - // Holds information that may help speed up compilation - static class CompilationInfoCache { - - private Map archivePackageCache; - - static class ArchiveInfo { - - // The packages identified in a particular archive - private List packageNames; - - private boolean isBootJar = false; - - public ArchiveInfo(List packageNames, boolean isBootJar) { - this.packageNames = packageNames; - Collections.sort(this.packageNames); - this.isBootJar = isBootJar; - } - - public List getPackageNames() { - return packageNames; - } - - public boolean isBootJar() { - return isBootJar; - } - - public boolean containsPackage(String packageName, boolean subpackageMatchesAllowed) { - if (subpackageMatchesAllowed) { - for (String candidatePackageName: packageNames) { - if (candidatePackageName.startsWith(packageName)) { - return true; - } - } - return false; - } else { - // Must be an exact match, fast binary search: - int pos = Collections.binarySearch(packageNames, packageName); - return (pos >= 0); - } - } - } - - ArchiveInfo getArchiveInfoFor(File archive) { - if (!archive.isFile() || !(archive.getName().endsWith(".zip") || archive.getName().endsWith(".jar"))) { - // it is not an archive - return null; - } - if (archivePackageCache == null) { - archivePackageCache = new HashMap<>(); - } - try { - ArchiveInfo result = archivePackageCache.get(archive); - if (result == null) { - result = buildArchiveInfo(archive); - archivePackageCache.put(archive, result); - } - return result; - } catch (Exception e) { - throw new IllegalStateException("Unexpected problem caching entries from "+archive.getName(), e); - } - } - - private boolean packageCacheInitialized = false; - private Map packageCache = new HashMap(); - private ArchiveInfo moduleArchiveInfo; - - private class PackageCacheBuilderVisitor extends SimpleFileVisitor { - - @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { - if (file.getNameCount() > 3 && file.toString().endsWith(".class")) { - int fnc = file.getNameCount(); - if (fnc > 3) { // There is a package name - e.g. /modules/java.base/java/lang/Object.class - Path packagePath = file.subpath(2, fnc-1); // e.g. java/lang - String packagePathString = packagePath.toString()+"/"; - packageCache.put(packagePathString, file.subpath(0, fnc-1)); // java/lang -> /modules/java.base/java/lang - } - } - return FileVisitResult.CONTINUE; - } - } - - private synchronized ArchiveInfo buildPackageMap() { - if (!packageCacheInitialized) { - packageCacheInitialized = true; - Iterable roots = getJrtFs().getRootDirectories(); - PackageCacheBuilderVisitor visitor = new PackageCacheBuilderVisitor(); - try { - for (java.nio.file.Path path : roots) { - Files.walkFileTree(path, visitor); - } - } catch (IOException e) { - throw new RuntimeException(e); - } - List ls = new ArrayList<>(); - ls.addAll(packageCache.keySet()); - Collections.sort(ls); - moduleArchiveInfo = new ArchiveInfo(ls, false); - } - return moduleArchiveInfo; - } - - /** - * Walk the specified archive and collect up the package names of any .class files encountered. If - * the archive contains nested jars packaged in a BOOT style way (under a BOOT-INF/lib folder) then - * walk those too and include relevant packages. - * - * @param file archive file to discover packages from - * @return an ArchiveInfo encapsulating package info from the archive - */ - private ArchiveInfo buildArchiveInfo(File file) { - if (file.toString().endsWith("jrt-fs.jar")) { - // Special treatment for >=JDK9 - treat this as intention to use modules - return buildPackageMap(); - } - List packageNames = new ArrayList<>(); - boolean isBootJar = false; - try (ZipFile openArchive = new ZipFile(file)) { - Enumeration entries = openArchive.entries(); - while (entries.hasMoreElements()) { - ZipEntry entry = entries.nextElement(); - String name = entry.getName(); - if (name.endsWith(".class")) { - if (name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES)) { - isBootJar = true; - int idx = name.lastIndexOf('/') + 1; - if (idx != 0 ) { - if (idx == BOOT_PACKAGING_PREFIX_FOR_CLASSES.length()) { - // default package - packageNames.add("/"); - } else { - // Normalize to forward slashes - name = name.substring(BOOT_PACKAGING_PREFIX_FOR_CLASSES.length(), idx); - name = name.replace('\\', '/'); - packageNames.add(name); - } - } - } else { - int idx = name.lastIndexOf('/') + 1; - if (idx != 0 ) { - // Normalize to forward slashes - name = name.replace('\\', '/'); - name = name.substring(0, idx); - packageNames.add(name); - } else if (idx == 0) { - // default package entries in here - packageNames.add("/"); - } - } - } else if (name.startsWith(BOOT_PACKAGING_PREFIX_FOR_LIBRARIES) && name.endsWith(".jar")) { - isBootJar = true; - try (ZipInputStream zis = new ZipInputStream(openArchive.getInputStream(entry))) { - Enumeration nestedZipEnumerator = new ZipEnumerator(zis); - while (nestedZipEnumerator.hasMoreElements()) { - ZipEntry innerEntry = nestedZipEnumerator.nextElement(); - String innerEntryName = innerEntry.getName(); - if (innerEntryName.endsWith(".class")) { - int idx = innerEntryName.lastIndexOf('/') + 1; - if (idx != 0 ) { - // Normalize to forward slashes - innerEntryName = innerEntryName.replace('\\', '/'); - innerEntryName = innerEntryName.substring(0, idx); - packageNames.add(innerEntryName); - } else if (idx == 0) { - // default package entries in here - packageNames.add("/"); - } - } - } - } - } - } - } catch (IOException ioe) { - throw new IllegalStateException("Unexpected problem determining packages in "+file,ioe); - } - return new ArchiveInfo(packageNames, isBootJar); - } - - } - - static class Key { - private Location location; - private String classpath; - private String packageName; - private Set kinds; - private boolean recurse; - - public Key(Location location, String classpath, String packageName, Set kinds, boolean recurse) { - this.location = location; - this.classpath = classpath; - this.packageName = packageName; - this.kinds = kinds; - this.recurse = recurse; - } - - @Override - public int hashCode() { - return (((location.hashCode()*37)+classpath.hashCode()*37+(packageName==null?0:packageName.hashCode()))*37+kinds.hashCode())*37+(recurse?1:0); - } - - @Override - public boolean equals(Object obj) { - if (!(obj instanceof Key)) { - return false; - } - Key that = (Key)obj; - return location.equals(that.location) && - classpath.equals(that.classpath) && - kinds.equals(that.kinds) && - (recurse==that.recurse) && - (packageName==null?(that.packageName==null):this.packageName.equals(that.packageName)); - } - } - private String getPlatformClassPath() { - if (platformClasspath == null) { - platformClasspath = System.getProperty("sun.boot.class.path"); + if (this.platformClasspath == null) { + this.platformClasspath = System.getProperty("sun.boot.class.path"); } - if (platformClasspath == null) { - platformClasspath = ""; + if (this.platformClasspath == null) { + this.platformClasspath = ""; } - return platformClasspath; + return this.platformClasspath; } @Override @@ -335,26 +137,29 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { logger.debug("list({},{},{},{})", location, packageName, kinds, recurse); String classpath = ""; Path moduleRootPath = null; - if (location instanceof JDKModuleLocation && (kinds == null || kinds.contains(Kind.CLASS))) { + if (location instanceof JDKModuleLocation + && (kinds == null || kinds.contains(Kind.CLASS))) { // list(org.springframework.cloud.function.compiler.java.MemoryBasedJavaFileManager$JDKModuleLocation@550a1967, - // java.lang,[SOURCE, CLASS, HTML, OTHER],false) - moduleRootPath = ((JDKModuleLocation)location).getModuleRootPath(); - logger.debug("For JDKModuleLocation "+location.toString()+" root path is "+moduleRootPath); - } else if (location == StandardLocation.PLATFORM_CLASS_PATH + // java.lang,[SOURCE, CLASS, HTML, OTHER],false) + moduleRootPath = ((JDKModuleLocation) location).getModuleRootPath(); + logger.debug("For JDKModuleLocation " + location.toString() + " root path is " + + moduleRootPath); + } + else if (location == StandardLocation.PLATFORM_CLASS_PATH && (kinds == null || kinds.contains(Kind.CLASS))) { classpath = getPlatformClassPath(); -// if (classpath.length() == 0) { -// if (hasJrtFsPath()) { -// classpath = getJrtFsPath(); -// } -// } + // if (classpath.length() == 0) { + // if (hasJrtFsPath()) { + // classpath = getJrtFsPath(); + // } + // } logger.debug("Creating iterable for boot class path: {}", classpath); } else if (location == StandardLocation.CLASS_PATH && (kinds == null || kinds.contains(Kind.CLASS))) { String javaClassPath = getClassPath(); - if (!resolvedAdditionalDependencies.isEmpty()) { - for (File resolvedAdditionalDependency : resolvedAdditionalDependencies + if (!this.resolvedAdditionalDependencies.isEmpty()) { + for (File resolvedAdditionalDependency : this.resolvedAdditionalDependencies .values()) { javaClassPath += File.pathSeparatorChar + resolvedAdditionalDependency .toURI().toString().substring("file:".length()); @@ -364,41 +169,28 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { logger.debug("Creating iterable for class path: {}", classpath); } Key k = new Key(location, classpath, packageName, kinds, recurse); - CloseableFilterableJavaFileObjectIterable resultIterable = iterables.get(k); + CloseableFilterableJavaFileObjectIterable resultIterable = this.iterables.get(k); if (resultIterable == null) { if (moduleRootPath != null) { - resultIterable = new IterableJrtModule(compilationInfoCache, moduleRootPath, packageName, recurse); - } else { - resultIterable = new IterableClasspath(compilationInfoCache, classpath, packageName, recurse); + resultIterable = new IterableJrtModule(this.compilationInfoCache, + moduleRootPath, packageName, recurse); } - iterables.put(k, resultIterable); + else { + resultIterable = new IterableClasspath(this.compilationInfoCache, + classpath, packageName, recurse); + } + this.iterables.put(k, resultIterable); } resultIterable.reset(); return resultIterable; } private String getClassPath() { - if (classpath == null) { + if (this.classpath == null) { ClassLoader loader = InMemoryJavaFileObject.class.getClassLoader(); String cp = null; if (loader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) loader).getURLs(); - if (urls.length > 1) { // heuristic that catches Maven surefire tests - if (!urls[0].toString().startsWith("jar:file:")) { // heuristic for Spring Boot fat jar - StringBuilder builder = new StringBuilder(); - for (URL url : urls) { - if (builder.length() > 0) { - builder.append(File.pathSeparator); - } - String path = url.toString(); - if (path.startsWith("file:")) { - path = path.substring("file:".length()); - } - builder.append(path); - } - cp = builder.toString(); - } - } + cp = classPath((URLClassLoader) loader, cp); } if (cp == null) { cp = System.getProperty("java.class.path"); @@ -406,9 +198,32 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { if (hasJrtFsPath()) { cp = cp + File.pathSeparator + getJrtFsPath(); } - classpath = pathWithPlatformClassPathRemoved(cp); + this.classpath = pathWithPlatformClassPathRemoved(cp); } - return classpath; + return this.classpath; + } + + private String classPath(URLClassLoader loader, String cp) { + URL[] urls = loader.getURLs(); + if (urls.length > 1) { // heuristic that catches Maven surefire tests + if (!urls[0].toString().startsWith("jar:file:")) { // heuristic for + // Spring Boot fat + // jar + StringBuilder builder = new StringBuilder(); + for (URL url : urls) { + if (builder.length() > 0) { + builder.append(File.pathSeparator); + } + String path = url.toString(); + if (path.startsWith("file:")) { + path = path.substring("file:".length()); + } + builder.append(path); + } + cp = builder.toString(); + } + } + return cp; } // remove the platform classpath entries, they will be search separately (and earlier) @@ -417,7 +232,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { Set cps = toList(classpath); cps.removeAll(pcps); StringBuilder builder = new StringBuilder(); - for (String cpe: cps) { + for (String cpe : cps) { if (builder.length() > 0) { builder.append(File.pathSeparator); } @@ -428,7 +243,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { private Set toList(String path) { Set result = new LinkedHashSet<>(); - StringTokenizer tokenizer = new StringTokenizer(path,File.pathSeparator); + StringTokenizer tokenizer = new StringTokenizer(path, File.pathSeparator); while (tokenizer.hasMoreTokens()) { result.add(tokenizer.nextToken()); } @@ -484,7 +299,8 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { sibling); // Example parameters: CLASS_OUTPUT, Foo, CLASS, // StringBasedJavaSourceFileObject[string:///a/b/c/Foo.java] - return outputCollector.getJavaFileForOutput(location, className, kind, sibling); + return this.outputCollector.getJavaFileForOutput(location, className, kind, + sibling); } @Override @@ -502,7 +318,7 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { // This can be called when the annotation config processor runs // Example parameters: CLASS_OUTPUT, , // META-INF/spring-configuration-metadata.json, null - return outputCollector.getFileForOutput(location, packageName, relativeName, + return this.outputCollector.getFileForOutput(location, packageName, relativeName, sibling); } @@ -512,14 +328,15 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { @Override public void close() throws IOException { - Collection toClose = iterables.values(); - for (CloseableFilterableJavaFileObjectIterable icp: toClose) { + Collection toClose = this.iterables + .values(); + for (CloseableFilterableJavaFileObjectIterable icp : toClose) { icp.close(); } } public List getCompiledClasses() { - return outputCollector.getCompiledClasses(); + return this.outputCollector.getCompiledClasses(); } public List addAndResolveDependencies(String[] dependencies) { @@ -536,16 +353,19 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { // dependency = // maven://org.springframework:spring-expression:4.3.9.RELEASE // resolved.toURI() = - // file:/Users/aclement/.m2/repository/org/springframework/spring-expression/4.3.9.RELEASE/spring-expression-4.3.9.RELEASE.jar - resolvedAdditionalDependencies.put(dependency, resolved); + // file:/Users/aclement/.m2/repository/ + // org/springframework/spring-expression/4.3.9.RELEASE/spring-expression-4.3.9.RELEASE.jar + this.resolvedAdditionalDependencies.put(dependency, resolved); } catch (RuntimeException re) { CompilationMessage compilationMessage = new CompilationMessage( CompilationMessage.Kind.ERROR, re.getMessage(), null, 0, 0); resolutionMessages.add(compilationMessage); } - } else if (dependency.startsWith("file:")) { - resolvedAdditionalDependencies.put(dependency, new File(URI.create(dependency))); + } + else if (dependency.startsWith("file:")) { + this.resolvedAdditionalDependencies.put(dependency, + new File(URI.create(dependency))); } else { resolutionMessages.add(new CompilationMessage( @@ -559,18 +379,320 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { } public Map getResolvedAdditionalDependencies() { - return resolvedAdditionalDependencies; + return this.resolvedAdditionalDependencies; + } + + public String inferModuleName(Location location) throws IOException { + if (location instanceof JDKModuleLocation) { + JDKModuleLocation m = (JDKModuleLocation) location; + return m.getModuleName(); + } + throw new IllegalStateException( + "Asked to inferModuleName from a " + location.getClass().getName()); + } + + private boolean hasJrtFsPath() { + return getJrtFsPath() != null; + } + + private String getJrtFsPath() { + if (!this.checkedForJrtFsPath) { + String javaHome = System.getProperty("java.home"); + String jrtFsFilePath = javaHome + File.separator + "lib" + File.separator + + "jrt-fs.jar"; + File jrtFsFile = new File(jrtFsFilePath); + if (jrtFsFile.exists()) { + this.jrtFsFilePath = jrtFsFilePath; + } + this.checkedForJrtFsPath = true; + } + return this.jrtFsFilePath; + } + + public Iterable> listLocationsForModules(Location location) + throws IOException { + if (getJrtFsPath() != null + && location == StandardLocation.valueOf("SYSTEM_MODULES")) { + Set> ss = new HashSet<>(); + HashSet moduleLocations = new HashSet<>(); + ModuleIdentifierVisitor visitor = new ModuleIdentifierVisitor(); + Iterable roots = getJrtFs().getRootDirectories(); + try { + for (Path path : roots) { + Files.walkFileTree(path, visitor); + } + moduleLocations.addAll(visitor.getModuleLocations()); + } + catch (IOException ioe) { + throw new RuntimeException(ioe); + } + ss.add(moduleLocations); + return ss; + } + else { + return Collections.emptySet(); + } + } + + // Holds information that may help speed up compilation + static class CompilationInfoCache { + + private Map archivePackageCache; + + private boolean packageCacheInitialized = false; + + private Map packageCache = new HashMap(); + + private ArchiveInfo moduleArchiveInfo; + + ArchiveInfo getArchiveInfoFor(File archive) { + if (!archive.isFile() || !(archive.getName().endsWith(".zip") + || archive.getName().endsWith(".jar"))) { + // it is not an archive + return null; + } + if (this.archivePackageCache == null) { + this.archivePackageCache = new HashMap<>(); + } + try { + ArchiveInfo result = this.archivePackageCache.get(archive); + if (result == null) { + result = buildArchiveInfo(archive); + this.archivePackageCache.put(archive, result); + } + return result; + } + catch (Exception e) { + throw new IllegalStateException( + "Unexpected problem caching entries from " + archive.getName(), + e); + } + } + + private synchronized ArchiveInfo buildPackageMap() { + if (!this.packageCacheInitialized) { + this.packageCacheInitialized = true; + Iterable roots = getJrtFs().getRootDirectories(); + PackageCacheBuilderVisitor visitor = new PackageCacheBuilderVisitor(); + try { + for (java.nio.file.Path path : roots) { + Files.walkFileTree(path, visitor); + } + } + catch (IOException e) { + throw new RuntimeException(e); + } + List ls = new ArrayList<>(); + ls.addAll(this.packageCache.keySet()); + Collections.sort(ls); + this.moduleArchiveInfo = new ArchiveInfo(ls, false); + } + return this.moduleArchiveInfo; + } + + /** + * Walk the specified archive and collect up the package names of any .class files + * encountered. If the archive contains nested jars packaged in a BOOT style way + * (under a BOOT-INF/lib folder) then walk those too and include relevant + * packages. + * @param file archive file to discover packages from + * @return an ArchiveInfo encapsulating package info from the archive + */ + private ArchiveInfo buildArchiveInfo(File file) { + if (file.toString().endsWith("jrt-fs.jar")) { + // Special treatment for >=JDK9 - treat this as intention to use modules + return buildPackageMap(); + } + List packageNames = new ArrayList<>(); + boolean isBootJar = false; + try (ZipFile openArchive = new ZipFile(file)) { + Enumeration entries = openArchive.entries(); + while (entries.hasMoreElements()) { + ZipEntry entry = entries.nextElement(); + String name = entry.getName(); + if (name.endsWith(".class")) { + if (name.startsWith(BOOT_PACKAGING_PREFIX_FOR_CLASSES)) { + isBootJar = true; + int idx = name.lastIndexOf('/') + 1; + if (idx != 0) { + if (idx == BOOT_PACKAGING_PREFIX_FOR_CLASSES.length()) { + // default package + packageNames.add("/"); + } + else { + // Normalize to forward slashes + name = name.substring( + BOOT_PACKAGING_PREFIX_FOR_CLASSES.length(), + idx); + name = name.replace('\\', '/'); + packageNames.add(name); + } + } + } + else { + int idx = name.lastIndexOf('/') + 1; + if (idx != 0) { + // Normalize to forward slashes + name = name.replace('\\', '/'); + name = name.substring(0, idx); + packageNames.add(name); + } + else if (idx == 0) { + // default package entries in here + packageNames.add("/"); + } + } + } + else if (name.startsWith(BOOT_PACKAGING_PREFIX_FOR_LIBRARIES) + && name.endsWith(".jar")) { + isBootJar = true; + try (ZipInputStream zis = new ZipInputStream( + openArchive.getInputStream(entry))) { + Enumeration nestedZipEnumerator = new ZipEnumerator( + zis); + while (nestedZipEnumerator.hasMoreElements()) { + ZipEntry innerEntry = nestedZipEnumerator.nextElement(); + String innerEntryName = innerEntry.getName(); + if (innerEntryName.endsWith(".class")) { + int idx = innerEntryName.lastIndexOf('/') + 1; + if (idx != 0) { + // Normalize to forward slashes + innerEntryName = innerEntryName.replace('\\', + '/'); + innerEntryName = innerEntryName.substring(0, idx); + packageNames.add(innerEntryName); + } + else if (idx == 0) { + // default package entries in here + packageNames.add("/"); + } + } + } + } + } + } + } + catch (IOException ioe) { + throw new IllegalStateException( + "Unexpected problem determining packages in " + file, ioe); + } + return new ArchiveInfo(packageNames, isBootJar); + } + + static class ArchiveInfo { + + // The packages identified in a particular archive + private List packageNames; + + private boolean isBootJar = false; + + ArchiveInfo(List packageNames, boolean isBootJar) { + this.packageNames = packageNames; + Collections.sort(this.packageNames); + this.isBootJar = isBootJar; + } + + public List getPackageNames() { + return this.packageNames; + } + + public boolean isBootJar() { + return this.isBootJar; + } + + public boolean containsPackage(String packageName, + boolean subpackageMatchesAllowed) { + if (subpackageMatchesAllowed) { + for (String candidatePackageName : this.packageNames) { + if (candidatePackageName.startsWith(packageName)) { + return true; + } + } + return false; + } + else { + // Must be an exact match, fast binary search: + int pos = Collections.binarySearch(this.packageNames, packageName); + return (pos >= 0); + } + } + + } + + private class PackageCacheBuilderVisitor extends SimpleFileVisitor { + + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { + if (file.getNameCount() > 3 && file.toString().endsWith(".class")) { + int fnc = file.getNameCount(); + if (fnc > 3) { // There is a package name - e.g. + // /modules/java.base/java/lang/Object.class + Path packagePath = file.subpath(2, fnc - 1); // e.g. java/lang + String packagePathString = packagePath.toString() + "/"; + CompilationInfoCache.this.packageCache.put(packagePathString, + file.subpath(0, fnc - 1)); // java/lang + // -> + // /modules/java.base/java/lang + } + } + return FileVisitResult.CONTINUE; + } + + } + + } + + static class Key { + + private Location location; + + private String classpath; + + private String packageName; + + private Set kinds; + + private boolean recurse; + + Key(Location location, String classpath, String packageName, Set kinds, + boolean recurse) { + this.location = location; + this.classpath = classpath; + this.packageName = packageName; + this.kinds = kinds; + this.recurse = recurse; + } + + @Override + public int hashCode() { + return (((this.location.hashCode() * 37) + this.classpath.hashCode() * 37 + + (this.packageName == null ? 0 : this.packageName.hashCode())) * 37 + + this.kinds.hashCode()) * 37 + (this.recurse ? 1 : 0); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Key)) { + return false; + } + Key that = (Key) obj; + return this.location.equals(that.location) + && this.classpath.equals(that.classpath) + && this.kinds.equals(that.kinds) && (this.recurse == that.recurse) + && (this.packageName == null ? (that.packageName == null) + : this.packageName.equals(that.packageName)); + } + } - private static URI JRT_URI = URI.create("jrt:/"); - - private static FileSystem fs; - static class JDKModuleLocation implements Location { + private String moduleName; + private Path moduleRootPath; - - public JDKModuleLocation(String moduleName, Path moduleRootPath) { + + JDKModuleLocation(String moduleName, Path moduleRootPath) { this.moduleName = moduleName; this.moduleRootPath = moduleRootPath; } @@ -586,114 +708,62 @@ public class MemoryBasedJavaFileManager implements JavaFileManager { } public String getModuleName() { - return moduleName; + return this.moduleName; } - + public Path getModuleRootPath() { - return moduleRootPath; + return this.moduleRootPath; } - + public String toString() { - return "JDKModuleLocation(" + moduleName + ")"; + return "JDKModuleLocation(" + this.moduleName + ")"; } public int hashCode() { - return moduleName.hashCode(); + return this.moduleName.hashCode(); } - + public boolean equals(Object other) { if (!(other instanceof JDKModuleLocation)) { return false; } - return this.hashCode() == ((JDKModuleLocation)other).hashCode(); + return this.hashCode() == ((JDKModuleLocation) other).hashCode(); } - + } - - public String inferModuleName(Location location) throws IOException { - if (location instanceof JDKModuleLocation) { - JDKModuleLocation m = (JDKModuleLocation)location; - return m.getModuleName(); - } - throw new IllegalStateException("Asked to inferModuleName from a "+location.getClass().getName()); - } - + static class ModuleIdentifierVisitor extends SimpleFileVisitor { - + private Map modules = new HashMap<>(); - + @Override - public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + throws IOException { if (file.getNameCount() > 2 && file.toString().endsWith(".class")) { // /modules/jdk.rmic/sun/tools/tree/CaseStatement.class String moduleName = file.getName(1).toString(); // jdk.rmic Path moduleRootPath = file.subpath(0, 2); // /modules/jdk.rmic - if (!modules.containsKey(moduleName)) { - modules.put(moduleName, moduleRootPath); + if (!this.modules.containsKey(moduleName)) { + this.modules.put(moduleName, moduleRootPath); } } return FileVisitResult.CONTINUE; } public Set getModuleLocations() { - if (modules.size()==0) { + if (this.modules.size() == 0) { return Collections.emptySet(); - } else { + } + else { Set locations = new HashSet<>(); - for (Map.Entry moduleEntry: modules.entrySet()) { - locations.add(new JDKModuleLocation(moduleEntry.getKey(),moduleEntry.getValue())); + for (Map.Entry moduleEntry : this.modules.entrySet()) { + locations.add(new JDKModuleLocation(moduleEntry.getKey(), + moduleEntry.getValue())); } return locations; } } + } - private String jrtFsFilePath = null; - - private boolean checkedForJrtFsPath = false; - - private boolean hasJrtFsPath() { - return getJrtFsPath() != null; - } - - private String getJrtFsPath() { - if (!checkedForJrtFsPath) { - String javaHome = System.getProperty("java.home"); - String jrtFsFilePath = javaHome + File.separator + "lib" + File.separator + "jrt-fs.jar"; - File jrtFsFile = new File(jrtFsFilePath); - if (jrtFsFile.exists()) { - this.jrtFsFilePath = jrtFsFilePath; - } - checkedForJrtFsPath = true; - } - return jrtFsFilePath; - } - - public Iterable> listLocationsForModules(Location location) throws IOException { - if (getJrtFsPath()!=null && location == StandardLocation.valueOf("SYSTEM_MODULES")) { - Set> ss = new HashSet<>(); - HashSet moduleLocations = new HashSet<>(); - ModuleIdentifierVisitor visitor = new ModuleIdentifierVisitor(); - Iterable roots = getJrtFs().getRootDirectories(); - try { - for (Path path: roots) { - Files.walkFileTree(path, visitor); - } - moduleLocations.addAll(visitor.getModuleLocations()); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - ss.add(moduleLocations); - return ss; - } else { - return Collections.emptySet(); - } - } - - private static FileSystem getJrtFs() { - if (fs == null) { - fs = FileSystems.getFileSystem(JRT_URI); - } - return fs; - } } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/NestedZipEntryJavaFileObject.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/NestedZipEntryJavaFileObject.java index ea4521215..9a50f0a00 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/NestedZipEntryJavaFileObject.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/NestedZipEntryJavaFileObject.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -33,23 +33,27 @@ import javax.lang.model.element.NestingKind; import javax.tools.JavaFileObject; /** - * Represents an element inside in zip which is itself inside a zip. These objects are - * not initially created with the content of the file they represent, - * only enough information to find that content because many will - * typically be created but only few will be opened. - * + * Represents an element inside in zip which is itself inside a zip. These objects are not + * initially created with the content of the file they represent, only enough information + * to find that content because many will typically be created but only few will be + * opened. + * * @author Andy Clement */ public class NestedZipEntryJavaFileObject implements JavaFileObject { private File outerFile; + private ZipFile outerZipFile; + private ZipEntry innerZipFile; + private ZipEntry innerZipFileEntry; private URI uri; - public NestedZipEntryJavaFileObject(File outerFile, ZipFile outerZipFile, ZipEntry innerZipFile, ZipEntry innerZipFileEntry) { + public NestedZipEntryJavaFileObject(File outerFile, ZipFile outerZipFile, + ZipEntry innerZipFile, ZipEntry innerZipFileEntry) { this.outerFile = outerFile; this.outerZipFile = outerZipFile; this.innerZipFile = innerZipFile; @@ -58,48 +62,58 @@ public class NestedZipEntryJavaFileObject implements JavaFileObject { @Override public String getName() { - return innerZipFileEntry.getName(); // Example: a/b/C.class + return this.innerZipFileEntry.getName(); // Example: a/b/C.class } @Override public URI toUri() { - if (uri == null) { + if (this.uri == null) { String uriString = null; try { - uriString = "zip:"+outerFile.getAbsolutePath()+"!"+innerZipFile.getName()+"!"+innerZipFileEntry.getName(); - uri = new URI(uriString); - } catch (URISyntaxException e) { - throw new IllegalStateException("Unexpected URISyntaxException for string '"+uriString+"'",e); + uriString = "zip:" + this.outerFile.getAbsolutePath() + "!" + + this.innerZipFile.getName() + "!" + + this.innerZipFileEntry.getName(); + this.uri = new URI(uriString); + } + catch (URISyntaxException e) { + throw new IllegalStateException( + "Unexpected URISyntaxException for string '" + uriString + "'", + e); } } - return uri; + return this.uri; } - + @Override public InputStream openInputStream() throws IOException { // Find the inner zip file inside the outer zip file, then // find the relevant entry, then return the stream. - InputStream innerZipFileInputStream = this.outerZipFile.getInputStream(innerZipFile); + InputStream innerZipFileInputStream = this.outerZipFile + .getInputStream(this.innerZipFile); ZipInputStream innerZipInputStream = new ZipInputStream(innerZipFileInputStream); ZipEntry nextEntry = innerZipInputStream.getNextEntry(); while (nextEntry != null) { - if (nextEntry.getName().equals(innerZipFileEntry.getName())) { + if (nextEntry.getName().equals(this.innerZipFileEntry.getName())) { return innerZipInputStream; } nextEntry = innerZipInputStream.getNextEntry(); } - throw new IllegalStateException("Unable to locate nested zip entry "+innerZipFileEntry.getName()+" in zip "+innerZipFile.getName()+" inside zip "+outerZipFile.getName()); + throw new IllegalStateException( + "Unable to locate nested zip entry " + this.innerZipFileEntry.getName() + + " in zip " + this.innerZipFile.getName() + " inside zip " + + this.outerZipFile.getName()); } @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("getCharContent() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "getCharContent() not supported on class file: " + getName()); } @Override public long getLastModified() { - return innerZipFileEntry.getTime(); + return this.innerZipFileEntry.getTime(); } @Override @@ -112,15 +126,15 @@ public class NestedZipEntryJavaFileObject implements JavaFileObject { public boolean delete() { return false; // Cannot delete entries inside nested zips } - + @Override public OutputStream openOutputStream() throws IOException { - throw new IllegalStateException("cannot write to nested zip entry: "+toUri()); + throw new IllegalStateException("cannot write to nested zip entry: " + toUri()); } - + @Override public Writer openWriter() throws IOException { - throw new IllegalStateException("cannot write to nested zip entry: "+toUri()); + throw new IllegalStateException("cannot write to nested zip entry: " + toUri()); } @Override @@ -130,13 +144,14 @@ public class NestedZipEntryJavaFileObject implements JavaFileObject { } String name = getName(); int lastSlash = name.lastIndexOf('/'); - return name.substring(lastSlash+1).equals(simpleName+".class"); + return name.substring(lastSlash + 1).equals(simpleName + ".class"); } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("getCharContent() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "getCharContent() not supported on class file: " + getName()); } @Override @@ -148,25 +163,25 @@ public class NestedZipEntryJavaFileObject implements JavaFileObject { public Modifier getAccessLevel() { return null; // access level not known } - + @Override public int hashCode() { - int hc = outerFile.getName().hashCode(); - hc = hc * 37 + innerZipFile.getName().hashCode(); - hc = hc * 37 + innerZipFileEntry.getName().hashCode(); + int hc = this.outerFile.getName().hashCode(); + hc = hc * 37 + this.innerZipFile.getName().hashCode(); + hc = hc * 37 + this.innerZipFileEntry.getName().hashCode(); return hc; } - + @Override public boolean equals(Object obj) { if (!(obj instanceof NestedZipEntryJavaFileObject)) { return false; } - NestedZipEntryJavaFileObject that = (NestedZipEntryJavaFileObject)obj; - return (outerFile.getName().equals(that.outerFile.getName())) && - (innerZipFile.getName().equals(that.innerZipFile.getName())) && - (innerZipFileEntry.getName().equals(that.innerZipFileEntry.getName())); + NestedZipEntryJavaFileObject that = (NestedZipEntryJavaFileObject) obj; + return (this.outerFile.getName().equals(that.outerFile.getName())) + && (this.innerZipFile.getName().equals(that.innerZipFile.getName())) + && (this.innerZipFileEntry.getName() + .equals(that.innerZipFileEntry.getName())); } - -} \ No newline at end of file +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompiler.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompiler.java index dbcfc03ac..3fb2dc5bb 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompiler.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompiler.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2012-2019 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. @@ -39,73 +39,90 @@ import org.slf4j.LoggerFactory; */ public class RuntimeJavaCompiler { - private JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); - private static Logger logger = LoggerFactory.getLogger(RuntimeJavaCompiler.class); + private JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); + /** - * Compile the named class consisting of the supplied source code. If successful load the class - * and return it. Multiple classes may get loaded if the source code included anonymous/inner/local - * classes. + * Compile the named class consisting of the supplied source code. If successful load + * the class and return it. Multiple classes may get loaded if the source code + * included anonymous/inner/local classes. * @param className the name of the class (dotted form, e.g. com.foo.bar.Goo) * @param classSourceCode the full source code for the class - * @param dependencies optional coordinates for dependencies, maven 'maven://groupId:artifactId:version', or 'file:' URIs for local files - * @return a CompilationResult that encapsulates what happened during compilation (classes/messages produced) + * @param dependencies optional coordinates for dependencies, maven + * 'maven://groupId:artifactId:version', or 'file:' URIs for local files + * @return a CompilationResult that encapsulates what happened during compilation + * (classes/messages produced) */ - public CompilationResult compile(String className, String classSourceCode, String... dependencies) { - logger.info("Compiling source for class {} using compiler {}",className,compiler.getClass().getName()); + public CompilationResult compile(String className, String classSourceCode, + String... dependencies) { + logger.info("Compiling source for class {} using compiler {}", className, + this.compiler.getClass().getName()); DiagnosticCollector diagnosticCollector = new DiagnosticCollector(); MemoryBasedJavaFileManager fileManager = new MemoryBasedJavaFileManager(); - List resolutionMessages = fileManager.addAndResolveDependencies(dependencies); - JavaFileObject sourceFile = InMemoryJavaFileObject.getSourceJavaFileObject(className, classSourceCode); + List resolutionMessages = fileManager + .addAndResolveDependencies(dependencies); + JavaFileObject sourceFile = InMemoryJavaFileObject + .getSourceJavaFileObject(className, classSourceCode); Iterable compilationUnits = Arrays.asList(sourceFile); List options = new ArrayList<>(); options.add("-source"); options.add("1.8"); - CompilationTask task = compiler.getTask(null, fileManager , diagnosticCollector, options, null, compilationUnits); + CompilationTask task = this.compiler.getTask(null, fileManager, + diagnosticCollector, options, null, compilationUnits); boolean success = task.call(); CompilationResult compilationResult = new CompilationResult(success); compilationResult.recordCompilationMessages(resolutionMessages); - compilationResult.setResolvedAdditionalDependencies(new ArrayList<>(fileManager.getResolvedAdditionalDependencies().values())); + compilationResult.setResolvedAdditionalDependencies(new ArrayList<>( + fileManager.getResolvedAdditionalDependencies().values())); // If successful there may be no errors but there might be info/warnings - for (Diagnostic diagnostic : diagnosticCollector.getDiagnostics()) { - CompilationMessage.Kind kind = (diagnostic.getKind()==Kind.ERROR?CompilationMessage.Kind.ERROR:CompilationMessage.Kind.OTHER); -// String sourceCode = ((StringBasedJavaSourceFileObject)diagnostic.getSource()).getSourceCode(); - String sourceCode =null; + for (Diagnostic diagnostic : diagnosticCollector + .getDiagnostics()) { + CompilationMessage.Kind kind = (diagnostic.getKind() == Kind.ERROR + ? CompilationMessage.Kind.ERROR : CompilationMessage.Kind.OTHER); + // String sourceCode = + // ((StringBasedJavaSourceFileObject)diagnostic.getSource()).getSourceCode(); + String sourceCode = null; try { - sourceCode = (String)diagnostic.getSource().getCharContent(true); + sourceCode = (String) diagnostic.getSource().getCharContent(true); } catch (IOException ioe) { - // Unexpected, but leave sourceCode null to indicate it was not retrievable + // Unexpected, but leave sourceCode null to indicate it was not + // retrievable } catch (NullPointerException npe) { // TODO: should we skip warning diagnostics in the loop altogether? } - int startPosition = (int)diagnostic.getPosition(); + int startPosition = (int) diagnostic.getPosition(); if (startPosition == Diagnostic.NOPOS) { - startPosition = (int)diagnostic.getStartPosition(); + startPosition = (int) diagnostic.getStartPosition(); } - CompilationMessage compilationMessage = new CompilationMessage(kind,diagnostic.getMessage(null),sourceCode,startPosition,(int)diagnostic.getEndPosition()); + CompilationMessage compilationMessage = new CompilationMessage(kind, + diagnostic.getMessage(null), sourceCode, startPosition, + (int) diagnostic.getEndPosition()); compilationResult.recordCompilationMessage(compilationMessage); } if (success) { List ccds = fileManager.getCompiledClasses(); List> classes = new ArrayList<>(); - try (SimpleClassLoader ccl = new SimpleClassLoader(this.getClass().getClassLoader())) { - for (CompiledClassDefinition ccd: ccds) { + try (SimpleClassLoader ccl = new SimpleClassLoader( + this.getClass().getClassLoader())) { + for (CompiledClassDefinition ccd : ccds) { Class clazz = ccl.defineClass(ccd.getClassName(), ccd.getBytes()); classes.add(clazz); compilationResult.addClassBytes(ccd.getClassName(), ccd.getBytes()); } - } catch (IOException ioe) { - logger.debug("Unexpected exception defining classes",ioe); + } + catch (IOException ioe) { + logger.debug("Unexpected exception defining classes", ioe); } compilationResult.setCompiledClasses(classes); } return compilationResult; } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/SimpleClassLoader.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/SimpleClassLoader.java index dbc16a062..0bad72b90 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/SimpleClassLoader.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/SimpleClassLoader.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -23,7 +23,7 @@ import java.util.List; /** * Very simple classloader that can be used to load the compiled types. - * + * * @author Andy Clement */ public class SimpleClassLoader extends URLClassLoader { @@ -34,16 +34,18 @@ public class SimpleClassLoader extends URLClassLoader { super(NO_URLS, classLoader); } - public SimpleClassLoader(List resolvedAdditionalDependencies, ClassLoader classLoader) { + public SimpleClassLoader(List resolvedAdditionalDependencies, + ClassLoader classLoader) { super(toUrls(resolvedAdditionalDependencies), classLoader); } private static URL[] toUrls(List resolvedAdditionalDependencies) { URL[] urls = new URL[resolvedAdditionalDependencies.size()]; - for (int i=0,max=resolvedAdditionalDependencies.size();i defineClass(String name, byte[] bytes) { return super.defineClass(name, bytes, 0, bytes.length); } -} \ No newline at end of file + +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/ZipEntryJavaFileObject.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/ZipEntryJavaFileObject.java index 60ce4d7cd..fcdde4099 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/ZipEntryJavaFileObject.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/java/ZipEntryJavaFileObject.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -31,10 +31,17 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; import javax.tools.JavaFileObject; +/** + * A {@link JavaFileObject} that works on a ZIP entry. + * + * @author Mark Fisher + */ public class ZipEntryJavaFileObject implements JavaFileObject { private File containingFile; + private ZipFile zf; + private ZipEntry ze; private URI uri; @@ -47,26 +54,30 @@ public class ZipEntryJavaFileObject implements JavaFileObject { @Override public URI toUri() { - if (uri == null) { + if (this.uri == null) { String uriString = null; try { - uriString = "zip:" + containingFile.getAbsolutePath() + "!" + ze.getName(); - uri = new URI(uriString); - } catch (URISyntaxException e) { - throw new IllegalStateException("Unexpected URISyntaxException for string '" + uriString + "'", e); + uriString = "zip:" + this.containingFile.getAbsolutePath() + "!" + + this.ze.getName(); + this.uri = new URI(uriString); + } + catch (URISyntaxException e) { + throw new IllegalStateException( + "Unexpected URISyntaxException for string '" + uriString + "'", + e); } } - return uri; + return this.uri; } @Override public String getName() { - return ze.getName(); // a/b/C.class + return this.ze.getName(); // a/b/C.class } @Override public InputStream openInputStream() throws IOException { - return zf.getInputStream(ze); + return this.zf.getInputStream(this.ze); } @Override @@ -77,13 +88,15 @@ public class ZipEntryJavaFileObject implements JavaFileObject { @Override public Reader openReader(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("openReader() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "openReader() not supported on class file: " + getName()); } @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { // It is bytecode - throw new UnsupportedOperationException("getCharContent() not supported on class file: " + getName()); + throw new UnsupportedOperationException( + "getCharContent() not supported on class file: " + getName()); } @Override @@ -93,7 +106,7 @@ public class ZipEntryJavaFileObject implements JavaFileObject { @Override public long getLastModified() { - return ze.getTime(); + return this.ze.getTime(); } @Override @@ -128,19 +141,19 @@ public class ZipEntryJavaFileObject implements JavaFileObject { @Override public int hashCode() { - int hc = containingFile.getName().hashCode(); - hc = hc * 37 + ze.getName().hashCode(); + int hc = this.containingFile.getName().hashCode(); + hc = hc * 37 + this.ze.getName().hashCode(); return hc; } - + @Override public boolean equals(Object obj) { if (!(obj instanceof ZipEntryJavaFileObject)) { return false; } - ZipEntryJavaFileObject that = (ZipEntryJavaFileObject)obj; - return (containingFile.getName().equals(that.containingFile.getName())) && - (ze.getName().equals(that.ze.getName())); + ZipEntryJavaFileObject that = (ZipEntryJavaFileObject) obj; + return (this.containingFile.getName().equals(that.containingFile.getName())) + && (this.ze.getName().equals(that.ze.getName())); } -} \ No newline at end of file +} diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractByteCodeLoadingProxy.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractByteCodeLoadingProxy.java index 57e31a908..a9338cbf8 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractByteCodeLoadingProxy.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractByteCodeLoadingProxy.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -32,11 +32,13 @@ import org.springframework.util.ReflectionUtils; * @author Mark Fisher * @author Oleg Zhurakousky */ -abstract class AbstractByteCodeLoadingProxy implements InitializingBean, FunctionFactoryMetadata { +abstract class AbstractByteCodeLoadingProxy + implements InitializingBean, FunctionFactoryMetadata { private final Resource resource; - private final SimpleClassLoader classLoader = new SimpleClassLoader(AbstractByteCodeLoadingProxy.class.getClassLoader()); + private final SimpleClassLoader classLoader = new SimpleClassLoader( + AbstractByteCodeLoadingProxy.class.getClassLoader()); private T target; @@ -53,7 +55,8 @@ abstract class AbstractByteCodeLoadingProxy implements InitializingBean, Func String className = new ClassReader(bytes).getClassName().replace("/", "."); Class factoryClass = this.classLoader.defineClass(className, bytes); try { - this.target = ((CompilationResultFactory) factoryClass.newInstance()).getResult(); + this.target = ((CompilationResultFactory) factoryClass.newInstance()) + .getResult(); this.method = findFactoryMethod(factoryClass); } catch (InstantiationException | IllegalAccessException e) { @@ -81,4 +84,5 @@ abstract class AbstractByteCodeLoadingProxy implements InitializingBean, Func }); return method.get(); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractLambdaCompilingProxy.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractLambdaCompilingProxy.java index 532209fd1..07fc3cc01 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractLambdaCompilingProxy.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/AbstractLambdaCompilingProxy.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -29,9 +29,11 @@ import org.springframework.util.Assert; import org.springframework.util.FileCopyUtils; /** + * @param target type * @author Mark Fisher */ -public class AbstractLambdaCompilingProxy implements InitializingBean, BeanNameAware, FunctionFactoryMetadata { +public class AbstractLambdaCompilingProxy + implements InitializingBean, BeanNameAware, FunctionFactoryMetadata { private final Resource resource; @@ -43,7 +45,8 @@ public class AbstractLambdaCompilingProxy implements InitializingBean, BeanNa private String[] typeParameterizations; - public AbstractLambdaCompilingProxy(Resource resource, AbstractFunctionCompiler compiler) { + public AbstractLambdaCompilingProxy(Resource resource, + AbstractFunctionCompiler compiler) { Assert.notNull(resource, "Resource must not be null"); Assert.notNull(compiler, "Compiler must not be null"); this.resource = resource; @@ -61,8 +64,10 @@ public class AbstractLambdaCompilingProxy implements InitializingBean, BeanNa @Override public void afterPropertiesSet() throws Exception { - String lambda = FileCopyUtils.copyToString(new InputStreamReader(this.resource.getInputStream())); - this.factory = this.compiler.compile(this.beanName, lambda, this.typeParameterizations); + String lambda = FileCopyUtils + .copyToString(new InputStreamReader(this.resource.getInputStream())); + this.factory = this.compiler.compile(this.beanName, lambda, + this.typeParameterizations); } @Override @@ -74,4 +79,5 @@ public class AbstractLambdaCompilingProxy implements InitializingBean, BeanNa public Method getFactoryMethod() { return this.factory.getFactoryMethod(); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingConsumer.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingConsumer.java index 3728902bb..2f70f29c7 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingConsumer.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingConsumer.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -22,12 +22,12 @@ import org.springframework.cloud.function.core.FunctionFactoryMetadata; import org.springframework.core.io.Resource; /** + * @param type * @author Mark Fisher * @author Oleg Zhurakousky - * - * @param type */ -public class ByteCodeLoadingConsumer extends AbstractByteCodeLoadingProxy> implements FunctionFactoryMetadata>, Consumer { +public class ByteCodeLoadingConsumer extends AbstractByteCodeLoadingProxy> + implements FunctionFactoryMetadata>, Consumer { public ByteCodeLoadingConsumer(Resource resource) { super(resource); @@ -37,4 +37,5 @@ public class ByteCodeLoadingConsumer extends AbstractByteCodeLoadingProxy Function input type * @param Function result type + * @author Mark Fisher + * @author Oleg Zhurakousky */ -public class ByteCodeLoadingFunction extends AbstractByteCodeLoadingProxy> implements FunctionFactoryMetadata>, Function { +public class ByteCodeLoadingFunction + extends AbstractByteCodeLoadingProxy> + implements FunctionFactoryMetadata>, Function { public ByteCodeLoadingFunction(Resource resource) { super(resource); @@ -38,4 +39,5 @@ public class ByteCodeLoadingFunction extends AbstractByteCodeLoadingProxy< public R apply(T input) { return this.getTarget().apply(input); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingSupplier.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingSupplier.java index 70a72e1cb..b661cc5f8 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingSupplier.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingSupplier.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -22,12 +22,12 @@ import org.springframework.cloud.function.core.FunctionFactoryMetadata; import org.springframework.core.io.Resource; /** + * @param type * @author Mark Fisher * @author Oleg Zhurakousky - * - * @param type */ -public class ByteCodeLoadingSupplier extends AbstractByteCodeLoadingProxy> implements FunctionFactoryMetadata>, Supplier { +public class ByteCodeLoadingSupplier extends AbstractByteCodeLoadingProxy> + implements FunctionFactoryMetadata>, Supplier { public ByteCodeLoadingSupplier(Resource resource) { super(resource); @@ -37,4 +37,5 @@ public class ByteCodeLoadingSupplier extends AbstractByteCodeLoadingProxy input argument type * @author Mark Fisher */ -public class LambdaCompilingConsumer extends AbstractLambdaCompilingProxy> implements Consumer { +public class LambdaCompilingConsumer extends AbstractLambdaCompilingProxy> + implements Consumer { public LambdaCompilingConsumer(Resource resource, ConsumerCompiler compiler) { super(resource, compiler); @@ -34,4 +36,5 @@ public class LambdaCompilingConsumer extends AbstractLambdaCompilingProxy input argument type + * @param output argument type * @author Mark Fisher */ -public class LambdaCompilingFunction extends AbstractLambdaCompilingProxy> implements FunctionFactoryMetadata>, Function { +public class LambdaCompilingFunction + extends AbstractLambdaCompilingProxy> + implements FunctionFactoryMetadata>, Function { public LambdaCompilingFunction(Resource resource, FunctionCompiler compiler) { super(resource, compiler); @@ -35,4 +39,5 @@ public class LambdaCompilingFunction extends AbstractLambdaCompilingProxy< public R apply(T input) { return this.getTarget().apply(input); } + } diff --git a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/LambdaCompilingSupplier.java b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/LambdaCompilingSupplier.java index 97c48dbcb..d6b6c3772 100644 --- a/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/LambdaCompilingSupplier.java +++ b/spring-cloud-function-compiler/src/main/java/org/springframework/cloud/function/compiler/proxy/LambdaCompilingSupplier.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -23,9 +23,11 @@ import org.springframework.cloud.function.core.FunctionFactoryMetadata; import org.springframework.core.io.Resource; /** + * @param target type * @author Mark Fisher */ -public class LambdaCompilingSupplier extends AbstractLambdaCompilingProxy> implements FunctionFactoryMetadata>, Supplier { +public class LambdaCompilingSupplier extends AbstractLambdaCompilingProxy> + implements FunctionFactoryMetadata>, Supplier { public LambdaCompilingSupplier(Resource resource, SupplierCompiler compiler) { super(resource, compiler); @@ -35,4 +37,5 @@ public class LambdaCompilingSupplier extends AbstractLambdaCompilingProxy fc = new FunctionCompiler(String.class.getName()); - for (int i=0;i<5;i++) { + FunctionCompiler fc = new FunctionCompiler( + String.class.getName()); + for (int i = 0; i < 5; i++) { stime = System.currentTimeMillis(); - CompiledFunctionFactory> result = - fc.compile("foos", "flux -> flux.map(v -> v.toUpperCase())", "Flux", "Flux"); - assertThat(FunctionFactoryUtils.isFluxFunction(result.getFactoryMethod())).isTrue(); - System.out.println("Reusing FunctionCompiler: #"+(i+1)+" = "+(System.currentTimeMillis()-stime)+"ms"); + CompiledFunctionFactory> result = fc.compile("foos", + "flux -> flux.map(v -> v.toUpperCase())", "Flux", + "Flux"); + assertThat(FunctionFactoryUtils.isFluxFunction(result.getFactoryMethod())) + .isTrue(); + System.out.println("Reusing FunctionCompiler: #" + (i + 1) + " = " + + (System.currentTimeMillis() - stime) + "ms"); } - + // 3 separate FunctionCompilers: stime = System.currentTimeMillis(); CompiledFunctionFactory> compiled = new FunctionCompiler( - String.class.getName()).compile("foos", "flux -> flux.map(v -> v.toUpperCase())", "Flux", + String.class.getName()).compile("foos", + "flux -> flux.map(v -> v.toUpperCase())", "Flux", "Flux"); - assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())).isTrue(); + assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())) + .isTrue(); long etime = System.currentTimeMillis(); long time1 = (etime - stime); - System.out.println("New FunctionCompiler: "+time1+"ms"); - - stime = System.currentTimeMillis(); - compiled = new FunctionCompiler(String.class.getName()).compile("foos", - "flux -> flux.map(v -> v.toUpperCase())", "Flux", "Flux"); - assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())).isTrue(); - etime = System.currentTimeMillis(); - long time2 = (etime - stime); - System.out.println("New FunctionCompiler: "+time2+"ms"); + System.out.println("New FunctionCompiler: " + time1 + "ms"); stime = System.currentTimeMillis(); - compiled = new FunctionCompiler(String.class.getName()).compile("foos", - "flux -> flux.map(v -> v.toUpperCase())", "Flux", "Flux"); - assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())).isTrue(); + compiled = new FunctionCompiler(String.class.getName()).compile( + "foos", "flux -> flux.map(v -> v.toUpperCase())", "Flux", + "Flux"); + assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())) + .isTrue(); + etime = System.currentTimeMillis(); + long time2 = (etime - stime); + System.out.println("New FunctionCompiler: " + time2 + "ms"); + + stime = System.currentTimeMillis(); + compiled = new FunctionCompiler(String.class.getName()).compile( + "foos", "flux -> flux.map(v -> v.toUpperCase())", "Flux", + "Flux"); + assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())) + .isTrue(); etime = System.currentTimeMillis(); long time3 = (etime - stime); - System.out.println("New FunctionCompiler: "+time3+"ms"); + System.out.println("New FunctionCompiler: " + time3 + "ms"); } @Test public void usingJarNoPackageDecl() throws Exception { - ClassDescriptor tx = compile("TestX","public class TestX { public static String doit() { return \"TX\";}}\n"); + ClassDescriptor tx = compile("TestX", + "public class TestX { public static String doit() { return \"TX\";}}\n"); File jar = JarBuilder.create().addEntry(tx).getJar(); assertJarContents(jar, tx); CompilationResult result = new RuntimeJavaCompiler().compile("A", - "public class A {\n" + - " public static Object run() {\n" + - " return new TestX();\n" + - " }\n" + - "}", - jar.toURI().toString()); - assertTrue("Should be no problems: "+result.getCompilationMessages(), result.getCompilationMessages().isEmpty()); - try (URLClassLoader cl = new TestClassLoader(tx,descriptorFromResult(result))) { + "public class A {\n" + " public static Object run() {\n" + + " return new TestX();\n" + " }\n" + "}", + jar.toURI().toString()); + assertTrue("Should be no problems: " + result.getCompilationMessages(), + result.getCompilationMessages().isEmpty()); + try (URLClassLoader cl = new TestClassLoader(tx, descriptorFromResult(result))) { Class class1 = cl.loadClass("A"); Object invoke = class1.getDeclaredMethod("run").invoke(null); assertEquals(tx.name, invoke.getClass().getName()); } } - - // A class with no package declaration is placed under BOOT-INF/classes/ in a jar that is then used for resolution + // A class with no package declaration is placed under BOOT-INF/classes/ in a jar that + // is then used for resolution @Test public void usingJarNoPackageDeclBootInfClasses() throws Exception { - ClassDescriptor t1 = compile("TestX","public class TestX { public static String doit() { return \"TX\";}}\n"); - File jar = JarBuilder.create().addEntryWithPrefix("BOOT-INF/classes/",t1).getJar(); + ClassDescriptor t1 = compile("TestX", + "public class TestX { public static String doit() { return \"TX\";}}\n"); + File jar = JarBuilder.create().addEntryWithPrefix("BOOT-INF/classes/", t1) + .getJar(); assertJarContents(jar, "BOOT-INF/classes/", t1); CompilationResult result = new RuntimeJavaCompiler().compile("A", - "public class A {\n" + - " public static Object run() {\n" + - " return new TestX();\n" + - " }\n" + - "}", - jar.toURI().toString()); - assertTrue("Should be no problems: "+result.getCompilationMessages(), result.getCompilationMessages().isEmpty()); - try (URLClassLoader cl = new TestClassLoader(t1,descriptorFromResult(result))) { + "public class A {\n" + " public static Object run() {\n" + + " return new TestX();\n" + " }\n" + "}", + jar.toURI().toString()); + assertTrue("Should be no problems: " + result.getCompilationMessages(), + result.getCompilationMessages().isEmpty()); + try (URLClassLoader cl = new TestClassLoader(t1, descriptorFromResult(result))) { Class class1 = cl.loadClass("A"); Object invoke = class1.getDeclaredMethod("run").invoke(null); assertEquals(t1.name, invoke.getClass().getName()); } } - + // A class with no package declaration is placed in a jar which is then placed under // under BOOT-INF/lib/ in a jar that is then used for resolution @Test public void usingJarNoPackageDeclNestedBootInfLib() throws Exception { - ClassDescriptor t1 = compile("TestX","public class TestX { public static String doit() { return \"TX\";}}\n"); + ClassDescriptor t1 = compile("TestX", + "public class TestX { public static String doit() { return \"TX\";}}\n"); File jar = JarBuilder.create().addEntry(t1).getJar(); assertJarContents(jar, t1); // Now stick that jar in another jar! - File jar2 = JarBuilder.create().addEntry("BOOT-INF/lib/inner.jar",jar).getJar(); + File jar2 = JarBuilder.create().addEntry("BOOT-INF/lib/inner.jar", jar).getJar(); CompilationResult result = new RuntimeJavaCompiler().compile("A", - "public class A {\n" + - " public static Object run() {\n" + - " return new TestX();\n" + - " }\n" + - "}", - jar2.toURI().toString()); - assertTrue("Should be no problems: "+result.getCompilationMessages(), result.getCompilationMessages().isEmpty()); - try (URLClassLoader cl = new TestClassLoader(t1,descriptorFromResult(result))) { + "public class A {\n" + " public static Object run() {\n" + + " return new TestX();\n" + " }\n" + "}", + jar2.toURI().toString()); + assertTrue("Should be no problems: " + result.getCompilationMessages(), + result.getCompilationMessages().isEmpty()); + try (URLClassLoader cl = new TestClassLoader(t1, descriptorFromResult(result))) { Class class1 = cl.loadClass("A"); Object invoke = class1.getDeclaredMethod("run").invoke(null); assertEquals(t1.name, invoke.getClass().getName()); } } - - + // Build a jar containing a type with a package declaration and building against it @Test public void usingJarWithPackageDecl() throws Exception { @@ -192,15 +201,13 @@ public class CompilerDependencyResolutionTests { File jar = JarBuilder.create().addEntry(t1).getJar(); assertJarContents(jar, t1); CompilationResult result = new RuntimeJavaCompiler().compile("A", - "import " + t1.name.replace('$', '.') + ";\n" + - "public class A {\n" + - " public static Object run() {\n" + - " return new Test1();\n" + - " }\n" + - "}", - jar.toURI().toString()); - assertTrue("Should be no problems: "+result.getCompilationMessages(), result.getCompilationMessages().isEmpty()); - try (URLClassLoader cl = new TestClassLoader(t1,descriptorFromResult(result))) { + "import " + t1.name.replace('$', '.') + ";\n" + "public class A {\n" + + " public static Object run() {\n" + " return new Test1();\n" + + " }\n" + "}", + jar.toURI().toString()); + assertTrue("Should be no problems: " + result.getCompilationMessages(), + result.getCompilationMessages().isEmpty()); + try (URLClassLoader cl = new TestClassLoader(t1, descriptorFromResult(result))) { Class class1 = cl.loadClass("A"); Object invoke = class1.getDeclaredMethod("run").invoke(null); assertEquals(t1.name, invoke.getClass().getName()); @@ -211,24 +218,22 @@ public class CompilerDependencyResolutionTests { public void usingJarWithPackageDeclBootInfClasses() throws Exception { // Here the dependencies are under BOOT-INF/classes in the jar ClassDescriptor t1 = getTestClass("1"); - File jar = JarBuilder.create().addEntryWithPrefix("BOOT-INF/classes/",t1).getJar(); + File jar = JarBuilder.create().addEntryWithPrefix("BOOT-INF/classes/", t1) + .getJar(); assertJarContents(jar, "BOOT-INF/classes/", t1); CompilationResult result = new RuntimeJavaCompiler().compile("A", - "import " + t1.name.replace('$', '.') + ";\n" + - "public class A {\n" + - " public static Object run() {\n" + - " return new Test1();\n" + - " }\n" + - "}", - jar.toURI().toString()); - assertTrue("Should be no problems: "+result.getCompilationMessages(), result.getCompilationMessages().isEmpty()); - try (URLClassLoader cl = new TestClassLoader(t1,descriptorFromResult(result))) { + "import " + t1.name.replace('$', '.') + ";\n" + "public class A {\n" + + " public static Object run() {\n" + " return new Test1();\n" + + " }\n" + "}", + jar.toURI().toString()); + assertTrue("Should be no problems: " + result.getCompilationMessages(), + result.getCompilationMessages().isEmpty()); + try (URLClassLoader cl = new TestClassLoader(t1, descriptorFromResult(result))) { Class class1 = cl.loadClass("A"); Object invoke = class1.getDeclaredMethod("run").invoke(null); assertEquals(t1.name, invoke.getClass().getName()); } } - @Test public void usingJarWithPackageDeclNestedBootInfLib() throws Exception { @@ -237,17 +242,15 @@ public class CompilerDependencyResolutionTests { File jar = JarBuilder.create().addEntry(t1).getJar(); assertJarContents(jar, t1); // Now stick that jar in another jar! - File jar2 = JarBuilder.create().addEntry("BOOT-INF/lib/inner.jar",jar).getJar(); + File jar2 = JarBuilder.create().addEntry("BOOT-INF/lib/inner.jar", jar).getJar(); CompilationResult result = new RuntimeJavaCompiler().compile("A", - "import " + t1.name.replace('$', '.') + ";\n" + - "public class A {\n" + - " public static Object run() {\n" + - " return new Test1();\n" + - " }\n" + - "}", - jar2.toURI().toString()); - assertTrue("Should be no problems: "+result.getCompilationMessages(), result.getCompilationMessages().isEmpty()); - try (URLClassLoader cl = new TestClassLoader(t1,descriptorFromResult(result))) { + "import " + t1.name.replace('$', '.') + ";\n" + "public class A {\n" + + " public static Object run() {\n" + " return new Test1();\n" + + " }\n" + "}", + jar2.toURI().toString()); + assertTrue("Should be no problems: " + result.getCompilationMessages(), + result.getCompilationMessages().isEmpty()); + try (URLClassLoader cl = new TestClassLoader(t1, descriptorFromResult(result))) { Class class1 = cl.loadClass("A"); Object invoke = class1.getDeclaredMethod("run").invoke(null); assertEquals(t1.name, invoke.getClass().getName()); @@ -255,67 +258,42 @@ public class CompilerDependencyResolutionTests { } // --- - - // Simple classloader that can load from descriptors - class TestClassLoader extends URLClassLoader { - ClassDescriptor[] descriptors; - - public TestClassLoader(ClassDescriptor... descriptors) { - super(new URL[0], TestClassLoader.class.getClassLoader()); - this.descriptors = descriptors; - } - - @Override - protected Class findClass(String name) throws ClassNotFoundException { - for (ClassDescriptor descriptor: descriptors) { - if (descriptor.name.equals(name)) { - return defineClass(descriptor.name, descriptor.bytes, 0, descriptor.bytes.length); - } - } - return super.findClass(name); - } - - } - - // Simple holder for the result of compilation - static class ClassDescriptor { - final String name; - final byte[] bytes; - final Class clazz; - - public ClassDescriptor(String name, byte[] bytes, Class clazz) { - this.name = name; - this.bytes = bytes; - this.clazz = clazz; - } - } - private ClassDescriptor descriptorFromResult(CompilationResult result) { Class clazz = result.getCompiledClasses().get(0); - return new ClassDescriptor(clazz.getName(),result.getClassBytes(clazz.getName()),clazz); + return new ClassDescriptor(clazz.getName(), result.getClassBytes(clazz.getName()), + clazz); } private ClassDescriptor compile(String className, String classSourceCode) { - CompilationResult compile = new RuntimeJavaCompiler().compile(className, classSourceCode); - assertTrue("Should be empty: \n"+compile.getCompilationMessages(), compile.getCompilationMessages().isEmpty()); + CompilationResult compile = new RuntimeJavaCompiler().compile(className, + classSourceCode); + assertTrue("Should be empty: \n" + compile.getCompilationMessages(), + compile.getCompilationMessages().isEmpty()); Class clazz = compile.getCompiledClasses().get(0); - return new ClassDescriptor(clazz.getName(),compile.getClassBytes(clazz.getName()), compile.getCompiledClasses().get(0)); + return new ClassDescriptor(clazz.getName(), + compile.getClassBytes(clazz.getName()), + compile.getCompiledClasses().get(0)); } - + private ClassDescriptor getTestClass(String suffix) { try { - return compile("Test"+suffix,"package com.test;\npublic class Test"+suffix+" { public static String doit() { return \"T"+suffix+"\";}}\n"); - } catch (Exception e) { + return compile("Test" + suffix, + "package com.test;\npublic class Test" + suffix + + " { public static String doit() { return \"T" + suffix + + "\";}}\n"); + } + catch (Exception e) { throw new IllegalStateException(e); } } - + private void assertJarContents(File jar, ClassDescriptor... classdescriptors) { assertJarContents(jar, "", classdescriptors); } - private void assertJarContents(File jar, String prefix, ClassDescriptor... classDescriptors) { + private void assertJarContents(File jar, String prefix, + ClassDescriptor... classDescriptors) { List clazzes = new ArrayList<>(); for (ClassDescriptor classDescriptor : classDescriptors) { clazzes.add(prefix + classDescriptor.name.replace('.', '/') + ".class"); @@ -335,7 +313,8 @@ public class CompilerDependencyResolutionTests { fn.accept(nextJarEntry); } jarInputStream.close(); - } catch (IOException ioe) { + } + catch (IOException ioe) { ioe.printStackTrace(); } } @@ -348,31 +327,55 @@ public class CompilerDependencyResolutionTests { }); } + // Simple holder for the result of compilation + static class ClassDescriptor { + + final String name; + + final byte[] bytes; + + final Class clazz; + + public ClassDescriptor(String name, byte[] bytes, Class clazz) { + this.name = name; + this.bytes = bytes; + this.clazz = clazz; + } + + } + static class JarBuilder { File jarFile; + JarOutputStream jos; private JarBuilder() { try { File newJar = File.createTempFile("test", ".jar"); - jarFile = newJar.getAbsoluteFile(); + this.jarFile = newJar.getAbsoluteFile(); newJar.delete(); - jos = new JarOutputStream(new FileOutputStream(jarFile)); - jarFile.deleteOnExit(); - } catch (IOException e) { + this.jos = new JarOutputStream(new FileOutputStream(this.jarFile)); + this.jarFile.deleteOnExit(); + } + catch (IOException e) { throw new IllegalStateException("Unexpected problem creating file", e); } } + public static JarBuilder create() { + return new JarBuilder(); + } + public JarBuilder addEntry(String entryName, File entryContentFile) { try { ZipEntry ze = new ZipEntry(entryName); - jos.putNextEntry(ze); - jos.write(loadBytes(entryContentFile)); - jos.closeEntry(); + this.jos.putNextEntry(ze); + this.jos.write(loadBytes(entryContentFile)); + this.jos.closeEntry(); return this; - } catch (IOException e) { + } + catch (IOException e) { throw new IllegalStateException(e); } } @@ -386,7 +389,8 @@ public class CompilerDependencyResolutionTests { if (bs == null) { bs = new byte[readCount]; System.arraycopy(buf, 0, bs, 0, readCount); - } else { + } + else { byte[] newbs = new byte[bs.length + readCount]; System.arraycopy(bs, 0, newbs, 0, bs.length); System.arraycopy(buf, 0, newbs, bs.length, readCount); @@ -394,7 +398,8 @@ public class CompilerDependencyResolutionTests { } } return bs; - } catch (IOException ioe) { + } + catch (IOException ioe) { throw new IllegalStateException(ioe); } } @@ -414,26 +419,47 @@ public class CompilerDependencyResolutionTests { try { String n = holder.name.replace('.', '/') + ".class"; ZipEntry ze = new ZipEntry(prefix + n); - jos.putNextEntry(ze); - jos.write(holder.bytes); - jos.closeEntry(); + this.jos.putNextEntry(ze); + this.jos.write(holder.bytes); + this.jos.closeEntry(); return this; - } catch (IOException e) { + } + catch (IOException e) { throw new IllegalStateException(e); } } - public static JarBuilder create() { - return new JarBuilder(); - } - private File getJar() { try { - jos.close(); - } catch (IOException e) { + this.jos.close(); + } + catch (IOException e) { throw new IllegalStateException("Unable to close jar", e); } - return jarFile; + return this.jarFile; + } + + } + + // Simple classloader that can load from descriptors + class TestClassLoader extends URLClassLoader { + + ClassDescriptor[] descriptors; + + public TestClassLoader(ClassDescriptor... descriptors) { + super(new URL[0], TestClassLoader.class.getClassLoader()); + this.descriptors = descriptors; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + for (ClassDescriptor descriptor : this.descriptors) { + if (descriptor.name.equals(name)) { + return defineClass(descriptor.name, descriptor.bytes, 0, + descriptor.bytes.length); + } + } + return super.findClass(name); } } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/ConsumerCompilerTests.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/ConsumerCompilerTests.java index 9944020ea..48e746dda 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/ConsumerCompilerTests.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/ConsumerCompilerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -35,14 +35,16 @@ public class ConsumerCompilerTests { CompiledFunctionFactory> compiled = new ConsumerCompiler( String.class.getName()).compile("foos", "flux -> flux.subscribe(System.out::println)", "Flux"); - assertThat(FunctionFactoryUtils.isFluxConsumer(compiled.getFactoryMethod())).isTrue(); + assertThat(FunctionFactoryUtils.isFluxConsumer(compiled.getFactoryMethod())) + .isTrue(); } @Test public void consumesString() { CompiledFunctionFactory> compiled = new ConsumerCompiler( String.class.getName()).compile("foos", "System.out::println", "String"); - assertThat(FunctionFactoryUtils.isFluxConsumer(compiled.getFactoryMethod())).isFalse(); + assertThat(FunctionFactoryUtils.isFluxConsumer(compiled.getFactoryMethod())) + .isFalse(); } } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/FunctionCompilerTests.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/FunctionCompilerTests.java index 2b5251753..aacc9620a 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/FunctionCompilerTests.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/FunctionCompilerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -34,15 +34,19 @@ public class FunctionCompilerTests { public void transformsFluxString() { CompiledFunctionFactory> compiled = new FunctionCompiler( String.class.getName()).compile("foos", - "flux -> flux.map(v -> v.toUpperCase())", "Flux", "Flux"); - assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())).isTrue(); + "flux -> flux.map(v -> v.toUpperCase())", "Flux", + "Flux"); + assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())) + .isTrue(); } @Test public void transformsString() { CompiledFunctionFactory> compiled = new FunctionCompiler( - String.class.getName()).compile("foos", "v -> v.toUpperCase()", "String", "String"); - assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())).isFalse(); + String.class.getName()).compile("foos", "v -> v.toUpperCase()", "String", + "String"); + assertThat(FunctionFactoryUtils.isFluxFunction(compiled.getFactoryMethod())) + .isFalse(); assertThat(compiled.getResult().apply("hello")).isEqualTo("HELLO"); } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/SupplierCompilerTests.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/SupplierCompilerTests.java index fd04dbf53..752450da8 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/SupplierCompilerTests.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/SupplierCompilerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -36,15 +36,16 @@ public class SupplierCompilerTests { CompiledFunctionFactory> compiled = new SupplierCompiler( String.class.getName()).compile("foos", "() -> Flux.just(\"foo\", \"bar\")", "Flux"); - assertThat(FunctionFactoryUtils.isFluxSupplier(compiled.getFactoryMethod())).isTrue(); + assertThat(FunctionFactoryUtils.isFluxSupplier(compiled.getFactoryMethod())) + .isTrue(); } @Test public void supppliesString() { CompiledFunctionFactory> compiled = new SupplierCompiler( - String.class.getName()).compile("foos", - "() -> \"foo\"", "String"); - assertThat(FunctionFactoryUtils.isFluxSupplier(compiled.getFactoryMethod())).isFalse(); + String.class.getName()).compile("foos", "() -> \"foo\"", "String"); + assertThat(FunctionFactoryUtils.isFluxSupplier(compiled.getFactoryMethod())) + .isFalse(); assertThat(compiled.getResult().get()).isEqualTo("foo"); } @@ -52,9 +53,11 @@ public class SupplierCompilerTests { public void supppliesFluxStreamString() { CompiledFunctionFactory>> compiled = new SupplierCompiler>( String.class.getName()).compile("foos", - "() -> Flux.interval(Duration.ofMillis(1000)).map(Object::toString)", - "Flux"); - assertThat(FunctionFactoryUtils.isFluxSupplier(compiled.getFactoryMethod())).isTrue(); + "() -> Flux.interval(Duration.ofMillis(1000)).map(Object::toString)", + "Flux"); + assertThat(FunctionFactoryUtils.isFluxSupplier(compiled.getFactoryMethod())) + .isTrue(); assertThat(compiled.getResult().get().blockFirst()).isEqualTo("0"); } + } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompilerTests.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompilerTests.java index c89940c30..e08504df0 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompilerTests.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/java/RuntimeJavaCompilerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -16,9 +16,6 @@ package org.springframework.cloud.function.compiler.java; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import java.io.File; import java.util.List; import java.util.Locale; @@ -26,6 +23,9 @@ import java.util.function.Supplier; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** * @author Andy Clement */ @@ -39,27 +39,30 @@ public class RuntimeJavaCompilerTests { List compilationMessages = cr.getCompilationMessages(); assertTrue(compilationMessages.isEmpty()); } - + @Test public void missingType() throws Exception { Locale.setDefault(Locale.ENGLISH); RuntimeJavaCompiler rjc = new RuntimeJavaCompiler(); - CompilationResult cr = rjc.compile("A", - "public class A implements java.util.function.Supplier { "+ - " public String get() {\n"+ - " ExpressionParser parser = new SpelExpressionParser();\n" + - " Expression exp = parser.parseExpression(\"'Hello World'\");\n" + - " String message = (String) exp.getValue();"+ - " return message;\n"+ - " }\n"+ - "}"); + CompilationResult cr = rjc.compile("A", + "public class A implements java.util.function.Supplier { " + + " public String get() {\n" + + " ExpressionParser parser = new SpelExpressionParser();\n" + + " Expression exp = parser.parseExpression(\"'Hello World'\");\n" + + " String message = (String) exp.getValue();" + + " return message;\n" + " }\n" + "}"); List compilationMessages = cr.getCompilationMessages(); - assertEquals(3,compilationMessages.size()); - assertTrue(compilationMessages.get(0).getMessage().contains("cannot find symbol")); - assertTrue(compilationMessages.get(0).getMessage().contains("class ExpressionParser")); - assertTrue(compilationMessages.get(1).getMessage().contains("cannot find symbol")); - assertTrue(compilationMessages.get(1).getMessage().contains("class SpelExpressionParser")); - assertTrue(compilationMessages.get(2).getMessage().contains("cannot find symbol")); + assertEquals(3, compilationMessages.size()); + assertTrue( + compilationMessages.get(0).getMessage().contains("cannot find symbol")); + assertTrue(compilationMessages.get(0).getMessage() + .contains("class ExpressionParser")); + assertTrue( + compilationMessages.get(1).getMessage().contains("cannot find symbol")); + assertTrue(compilationMessages.get(1).getMessage() + .contains("class SpelExpressionParser")); + assertTrue( + compilationMessages.get(2).getMessage().contains("cannot find symbol")); assertTrue(compilationMessages.get(2).getMessage().contains("class Expression")); } @@ -67,57 +70,57 @@ public class RuntimeJavaCompilerTests { public void okWithImportedDependencies() throws Exception { RuntimeJavaCompiler rjc = new RuntimeJavaCompiler(); CompilationResult cr = rjc.compile("A", - "import org.springframework.expression.*;\n"+ - "import org.springframework.expression.spel.standard.*;\n"+ - "public class A implements java.util.function.Supplier {\n"+ - " public String get() {\n"+ - " ExpressionParser parser = new SpelExpressionParser();\n" + - " Expression exp = parser.parseExpression(\"'Hello World'\");\n" + - " String message = (String) exp.getValue();\n"+ - " return message;\n"+ - " }\n"+ - "}","maven://org.springframework:spring-expression:4.3.9.RELEASE"); + "import org.springframework.expression.*;\n" + + "import org.springframework.expression.spel.standard.*;\n" + + "public class A implements java.util.function.Supplier {\n" + + " public String get() {\n" + + " ExpressionParser parser = new SpelExpressionParser();\n" + + " Expression exp = parser.parseExpression(\"'Hello World'\");\n" + + " String message = (String) exp.getValue();\n" + + " return message;\n" + " }\n" + "}", + "maven://org.springframework:spring-expression:4.3.9.RELEASE"); List compilationMessages = cr.getCompilationMessages(); assertTrue(compilationMessages.isEmpty()); - try (SimpleClassLoader cl = new SimpleClassLoader(this.getClass().getClassLoader())) { - Class clazz = cl.defineClass("A",cr.getClassBytes("A")); + try (SimpleClassLoader cl = new SimpleClassLoader( + this.getClass().getClassLoader())) { + Class clazz = cl.defineClass("A", cr.getClassBytes("A")); Supplier supplier = (Supplier) clazz.newInstance(); - assertEquals("Hello World",supplier.get()); + assertEquals("Hello World", supplier.get()); } } @Test public void okWithImportedDependencies2() throws Exception { RuntimeJavaCompiler rjc = new RuntimeJavaCompiler(); - String source = - "import org.joda.time.*;\n"+ - "public class A implements java.util.function.Supplier {\n"+ - " public String get() {\n"+ - " DateTime dt = new DateTime();\n" + - " int month = dt.getMonthOfYear();\n"+ - " return String.valueOf(month>0);\n"+ - " }\n"+ - "}"; - CompilationResult cr = rjc.compile("A", source, "maven://joda-time:joda-time:2.9.9"); + String source = "import org.joda.time.*;\n" + + "public class A implements java.util.function.Supplier {\n" + + " public String get() {\n" + " DateTime dt = new DateTime();\n" + + " int month = dt.getMonthOfYear();\n" + + " return String.valueOf(month>0);\n" + " }\n" + "}"; + CompilationResult cr = rjc.compile("A", source, + "maven://joda-time:joda-time:2.9.9"); List compilationMessages = cr.getCompilationMessages(); assertTrue(compilationMessages.isEmpty()); - List resolvedAdditionalDependencies = cr.getResolvedAdditionalDependencies(); - try (SimpleClassLoader cl = new SimpleClassLoader(resolvedAdditionalDependencies, this.getClass().getClassLoader())) { - Class clazz = cl.defineClass("A",cr.getClassBytes("A")); + List resolvedAdditionalDependencies = cr + .getResolvedAdditionalDependencies(); + try (SimpleClassLoader cl = new SimpleClassLoader(resolvedAdditionalDependencies, + this.getClass().getClassLoader())) { + Class clazz = cl.defineClass("A", cr.getClassBytes("A")); Supplier supplier = (Supplier) clazz.newInstance(); - assertEquals("true",supplier.get()); + assertEquals("true", supplier.get()); } - + cr = rjc.compile("A", source, "maven://org.springframework:spring-expression:4.3.9.RELEASE", "maven://joda-time:joda-time:2.9.9"); compilationMessages = cr.getCompilationMessages(); assertTrue(compilationMessages.isEmpty()); resolvedAdditionalDependencies = cr.getResolvedAdditionalDependencies(); - try (SimpleClassLoader cl = new SimpleClassLoader(resolvedAdditionalDependencies, this.getClass().getClassLoader())) { - Class clazz = cl.defineClass("A",cr.getClassBytes("A")); + try (SimpleClassLoader cl = new SimpleClassLoader(resolvedAdditionalDependencies, + this.getClass().getClassLoader())) { + Class clazz = cl.defineClass("A", cr.getClassBytes("A")); Supplier supplier = (Supplier) clazz.newInstance(); - assertEquals("true",supplier.get()); + assertEquals("true", supplier.get()); } } @@ -125,34 +128,45 @@ public class RuntimeJavaCompilerTests { public void dependencyResolution() throws Exception { // Failure: RuntimeJavaCompiler rjc = new RuntimeJavaCompiler(); - CompilationResult cr = rjc.compile("A", - "public class A {}", - "maven://org.springframework:spring-expression2:4.3.9.RELEASE"); // extra '2' in there + CompilationResult cr = rjc.compile("A", "public class A {}", + "maven://org.springframework:spring-expression2:4.3.9.RELEASE"); // extra + // '2' + // in + // there List compilationMessages = cr.getCompilationMessages(); - assertEquals(1,compilationMessages.size()); - // ERROR:org.eclipse.aether.resolution.ArtifactResolutionException: Could not find artifact org.springframework:spring-expression2:jar:4.3.9.RELEASE in spring-snapshots (https://repo.spring.io/libs-snapshot) - assertTrue(compilationMessages.get(0).getMessage().contains("Could not find artifact org.springframework:spring-expression2:jar:4.3.9.RELEASE")); + assertEquals(1, compilationMessages.size()); + // ERROR:org.eclipse.aether.resolution.ArtifactResolutionException: Could not find + // artifact org.springframework:spring-expression2:jar:4.3.9.RELEASE in + // spring-snapshots (https://repo.spring.io/libs-snapshot) + assertTrue(compilationMessages.get(0).getMessage().contains( + "Could not find artifact org.springframework:spring-expression2:jar:4.3.9.RELEASE")); // Failure: rjc = new RuntimeJavaCompiler(); - cr = rjc.compile("A", - "public class A {}", - "trouble://org.springframework:spring-expression:4.3.9.RELEASE"); // rogue prefix (should be "maven:") + cr = rjc.compile("A", "public class A {}", + "trouble://org.springframework:spring-expression:4.3.9.RELEASE"); // rogue + // prefix + // (should + // be + // "maven:") compilationMessages = cr.getCompilationMessages(); - assertEquals(1,compilationMessages.size()); - assertTrue(compilationMessages.get(0).toString(),compilationMessages.get(0).getMessage().contains("Unrecognized dependency: ")); + assertEquals(1, compilationMessages.size()); + assertTrue(compilationMessages.get(0).toString(), compilationMessages.get(0) + .getMessage().contains("Unrecognized dependency: ")); // Success rjc = new RuntimeJavaCompiler(); - cr = rjc.compile("A", - "public class A {}", - "maven://joda-time:joda-time:2.9.9"); + cr = rjc.compile("A", "public class A {}", "maven://joda-time:joda-time:2.9.9"); compilationMessages = cr.getCompilationMessages(); - assertEquals(0,compilationMessages.size()); - List resolvedAdditionalDependencies = cr.getResolvedAdditionalDependencies(); + assertEquals(0, compilationMessages.size()); + List resolvedAdditionalDependencies = cr + .getResolvedAdditionalDependencies(); assertEquals(1, resolvedAdditionalDependencies.size()); - assertTrue("Expected this to end with 'joda-time-2.9.9.jar': "+resolvedAdditionalDependencies.get(0).toString(), - resolvedAdditionalDependencies.get(0).toString().endsWith("joda-time-2.9.9.jar")); + assertTrue( + "Expected this to end with 'joda-time-2.9.9.jar': " + + resolvedAdditionalDependencies.get(0).toString(), + resolvedAdditionalDependencies.get(0).toString() + .endsWith("joda-time-2.9.9.jar")); } } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingFunctionTests.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingFunctionTests.java index 522bafc79..0c7134e21 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingFunctionTests.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/compiler/proxy/ByteCodeLoadingFunctionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.junit.Test; +import reactor.core.publisher.Flux; import org.springframework.cloud.function.compiler.CompiledFunctionFactory; import org.springframework.cloud.function.compiler.ConsumerCompiler; @@ -32,8 +33,6 @@ import org.springframework.core.io.ByteArrayResource; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @author Oleg Zhurakousky @@ -44,11 +43,14 @@ public class ByteCodeLoadingFunctionTests { public void compileConsumer() throws Exception { CompiledFunctionFactory> compiled = new ConsumerCompiler( String.class.getName()).compile("foos", "System.out::println", "String"); - ByteArrayResource resource = new ByteArrayResource(compiled.getGeneratedClassBytes(), "foos"); - ByteCodeLoadingConsumer consumer = new ByteCodeLoadingConsumer<>(resource); + ByteArrayResource resource = new ByteArrayResource( + compiled.getGeneratedClassBytes(), "foos"); + ByteCodeLoadingConsumer consumer = new ByteCodeLoadingConsumer<>( + resource); consumer.afterPropertiesSet(); assertThat(consumer instanceof FunctionFactoryMetadata); - assertThat(FunctionFactoryUtils.isFluxConsumer(consumer.getFactoryMethod())).isFalse(); + assertThat(FunctionFactoryUtils.isFluxConsumer(consumer.getFactoryMethod())) + .isFalse(); consumer.accept("foo"); } @@ -56,35 +58,48 @@ public class ByteCodeLoadingFunctionTests { public void compileSupplier() throws Exception { CompiledFunctionFactory> compiled = new SupplierCompiler( String.class.getName()).compile("foos", "() -> \"foo\"", "String"); - ByteArrayResource resource = new ByteArrayResource(compiled.getGeneratedClassBytes(), "foos"); - ByteCodeLoadingSupplier supplier = new ByteCodeLoadingSupplier<>(resource); + ByteArrayResource resource = new ByteArrayResource( + compiled.getGeneratedClassBytes(), "foos"); + ByteCodeLoadingSupplier supplier = new ByteCodeLoadingSupplier<>( + resource); supplier.afterPropertiesSet(); assertThat(supplier instanceof FunctionFactoryMetadata); - assertThat(FunctionFactoryUtils.isFluxSupplier(supplier.getFactoryMethod())).isFalse(); + assertThat(FunctionFactoryUtils.isFluxSupplier(supplier.getFactoryMethod())) + .isFalse(); assertThat(supplier.get()).isEqualTo("foo"); } @Test public void compileFunction() throws Exception { CompiledFunctionFactory> compiled = new FunctionCompiler( - String.class.getName()).compile("foos", "v -> v.toUpperCase()", "String", "String"); - ByteArrayResource resource = new ByteArrayResource(compiled.getGeneratedClassBytes(), "foos"); - ByteCodeLoadingFunction function = new ByteCodeLoadingFunction<>(resource); + String.class.getName()).compile("foos", "v -> v.toUpperCase()", "String", + "String"); + ByteArrayResource resource = new ByteArrayResource( + compiled.getGeneratedClassBytes(), "foos"); + ByteCodeLoadingFunction function = new ByteCodeLoadingFunction<>( + resource); function.afterPropertiesSet(); assertThat(function instanceof FunctionFactoryMetadata); - assertThat(FunctionFactoryUtils.isFluxFunction(function.getFactoryMethod())).isFalse(); + assertThat(FunctionFactoryUtils.isFluxFunction(function.getFactoryMethod())) + .isFalse(); assertThat(function.apply("foo")).isEqualTo("FOO"); } @Test public void compileFluxFunction() throws Exception { CompiledFunctionFactory, Flux>> compiled = new FunctionCompiler, Flux>( - String.class.getName()).compile("foos", "flux -> flux.map(v -> v.toUpperCase())", "Flux", "Flux"); - ByteArrayResource resource = new ByteArrayResource(compiled.getGeneratedClassBytes(), "foos"); - ByteCodeLoadingFunction, Flux> function = new ByteCodeLoadingFunction<>(resource); + String.class.getName()).compile("foos", + "flux -> flux.map(v -> v.toUpperCase())", "Flux", + "Flux"); + ByteArrayResource resource = new ByteArrayResource( + compiled.getGeneratedClassBytes(), "foos"); + ByteCodeLoadingFunction, Flux> function = new ByteCodeLoadingFunction<>( + resource); function.afterPropertiesSet(); assertThat(function instanceof FunctionFactoryMetadata); - assertThat(FunctionFactoryUtils.isFluxFunction(function.getFactoryMethod())).isTrue(); + assertThat(FunctionFactoryUtils.isFluxFunction(function.getFactoryMethod())) + .isTrue(); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO"); } + } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtils.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtils.java index ccdd9aea8..ff07e823c 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtils.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -28,12 +28,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; -import reactor.core.publisher.Flux; - /** *

* Miscellaneous utility operations to interrogate functional components (beans) @@ -54,6 +53,7 @@ import reactor.core.publisher.Flux; public abstract class FunctionFactoryUtils { private static final String FLUX_CLASS_NAME = Flux.class.getName(); + private static final String PUBLISHER_CLASS_NAME = Publisher.class.getName(); private FunctionFactoryUtils() { @@ -142,4 +142,5 @@ public abstract class FunctionFactoryUtils { && Stream.of(types).allMatch(type -> type.startsWith(FLUX_CLASS_NAME) || type.startsWith(PUBLISHER_CLASS_NAME)); } + } diff --git a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtilsTests.java b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtilsTests.java index eb72b288e..10f83fe50 100644 --- a/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtilsTests.java +++ b/spring-cloud-function-compiler/src/test/java/org/springframework/cloud/function/core/FunctionFactoryUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,13 +23,12 @@ import java.util.function.Supplier; import org.junit.Test; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; import org.springframework.util.ReflectionUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -38,15 +37,17 @@ public class FunctionFactoryUtilsTests { @Test public void isFluxConsumer() { - Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, "fluxConsumer"); + Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, + "fluxConsumer"); assertThat(FunctionFactoryUtils.isFluxConsumer(method)).isTrue(); assertThat(FunctionFactoryUtils.isFluxSupplier(method)).isFalse(); assertThat(FunctionFactoryUtils.isFluxFunction(method)).isFalse(); } - + @Test public void isFluxSupplier() { - Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, "fluxSupplier"); + Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, + "fluxSupplier"); assertThat(FunctionFactoryUtils.isFluxSupplier(method)).isTrue(); assertThat(FunctionFactoryUtils.isFluxConsumer(method)).isFalse(); assertThat(FunctionFactoryUtils.isFluxFunction(method)).isFalse(); @@ -54,20 +55,22 @@ public class FunctionFactoryUtilsTests { @Test public void isFluxFunction() { - Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, "fluxFunction"); + Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, + "fluxFunction"); assertThat(FunctionFactoryUtils.isFluxFunction(method)).isTrue(); assertThat(FunctionFactoryUtils.isFluxSupplier(method)).isFalse(); assertThat(FunctionFactoryUtils.isFluxConsumer(method)).isFalse(); } - + @Test public void isReactiveFunction() { - Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, "reactiveFunction"); + Method method = ReflectionUtils.findMethod(FunctionFactoryUtilsTests.class, + "reactiveFunction"); assertThat(FunctionFactoryUtils.isFluxFunction(method)).isTrue(); assertThat(FunctionFactoryUtils.isFluxSupplier(method)).isFalse(); assertThat(FunctionFactoryUtils.isFluxConsumer(method)).isFalse(); } - + public Function, Flux> fluxFunction() { return foos -> foos.map(foo -> new Foo()); } @@ -83,7 +86,9 @@ public class FunctionFactoryUtilsTests { public Consumer> fluxConsumer() { return flux -> flux.subscribe(System.out::println); } - - class Foo {} + + class Foo { + + } } diff --git a/spring-cloud-function-context/pom.xml b/spring-cloud-function-context/pom.xml index 636921369..540db5e39 100644 --- a/spring-cloud-function-context/pom.xml +++ b/spring-cloud-function-context/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 spring-cloud-function-context @@ -73,12 +74,16 @@ java-compile compile - compile + + compile + java-test-compile test-compile - testCompile + + testCompile + diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractFunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractFunctionRegistry.java index 517fb1b19..f2a1f5cbe 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractFunctionRegistry.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/AbstractFunctionRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 the original author or authors. + * Copyright 2012-2019 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. @@ -22,9 +22,7 @@ import org.springframework.core.env.StandardEnvironment; import org.springframework.util.StringUtils; /** - * * @author Oleg Zhurakousky - * * @since 2.0.1 * */ @@ -33,12 +31,14 @@ public abstract class AbstractFunctionRegistry implements FunctionRegistry { @Autowired private Environment environment = new StandardEnvironment(); - public T lookup(Class type, String name) { - String functionDefinitionName = !StringUtils.hasText(name) && environment.containsProperty("spring.cloud.function.definition") - ? environment.getProperty("spring.cloud.function.definition") : name; + String functionDefinitionName = !StringUtils.hasText(name) + && this.environment.containsProperty("spring.cloud.function.definition") + ? this.environment.getProperty("spring.cloud.function.definition") + : name; return this.doLookup(type, functionDefinitionName); } protected abstract T doLookup(Class type, String name); + } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java index c8632c85d..7310643b6 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionCatalog.java @@ -1,11 +1,11 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -25,20 +25,20 @@ import java.util.Set; public interface FunctionCatalog { /** - * Will look up the instance of the functional interface by name only - * + * Will look up the instance of the functional interface by name only. + * @param instance type * @param name the name of the functional interface. Must not be null; * @return instance of the functional interface registered with this catalog */ - default public T lookup(String name) { + default T lookup(String name) { return this.lookup(null, name); } /** - * Will look up the instance of the functional interface by name and type - * which can only be Supplier, Consumer or Function. If type is not provided, the lookup - * will be made based on name only - * + * Will look up the instance of the functional interface by name and type which can + * only be Supplier, Consumer or Function. If type is not provided, the lookup will be + * made based on name only. + * @param instance type * @param type the type of functional interface. Can be null * @param name the name of the functional interface. Must not be null; * @return instance of the functional interface registered with this catalog @@ -48,11 +48,12 @@ public interface FunctionCatalog { Set getNames(Class type); /** - * Return the count of functions registered in this catalog + * Return the count of functions registered in this catalog. * @return the count of functions registered in this catalog */ default int size() { - throw new UnsupportedOperationException("This instance of FunctionCatalog does not support this operation"); + throw new UnsupportedOperationException( + "This instance of FunctionCatalog does not support this operation"); } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistration.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistration.java index 03f5a0899..0b5394c0c 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistration.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -27,6 +27,9 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import org.springframework.beans.factory.BeanNameAware; import org.springframework.cloud.function.core.FluxConsumer; import org.springframework.cloud.function.core.FluxFunction; @@ -34,26 +37,23 @@ import org.springframework.cloud.function.core.FluxSupplier; import org.springframework.util.Assert; import org.springframework.util.CollectionUtils; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** + * @param target type * @author Dave Syer * @author Oleg Zhurakousky */ public class FunctionRegistration implements BeanNameAware { - private T target; - private final Set names = new LinkedHashSet<>(); private final Map properties = new LinkedHashMap<>(); + private T target; + private FunctionType type; /** * Creates instance of FunctionRegistration. - * * @param target instance of {@link Supplier}, {@link Function} or {@link Consumer} * @param names additional set of names for this registration. Additional names can be * provided {@link #name(String)} or {@link #names(String...)} operations. @@ -65,15 +65,11 @@ public class FunctionRegistration implements BeanNameAware { } public Map getProperties() { - return properties; + return this.properties; } public Set getNames() { - return names; - } - - public FunctionType getType() { - return type; + return this.names; } /** @@ -81,15 +77,19 @@ public class FunctionRegistration implements BeanNameAware { * want to add a name or set or names to the existing set of names use * {@link #names(Collection)} or {@link #name(String)} or {@link #names(String...)} * operations. - * @param names + * @param names - bean names */ public void setNames(Set names) { this.names.clear(); this.names.addAll(names); } + public FunctionType getType() { + return this.type; + } + public T getTarget() { - return target; + return this.target; } public FunctionRegistration properties(Map properties) { @@ -133,7 +133,7 @@ public class FunctionRegistration implements BeanNameAware { } public FunctionRegistration wrap() { - if (type == null || type.isWrapper()) { + if (this.type == null || this.type.isWrapper()) { @SuppressWarnings("unchecked") FunctionRegistration value = (FunctionRegistration) this; return value; diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistry.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistry.java index dc788c872..f364e5edd 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistry.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java index 961dfec8e..8b789a6b8 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionType.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.context; import java.lang.reflect.ParameterizedType; @@ -23,18 +24,21 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import reactor.core.publisher.Flux; + import org.springframework.core.ResolvableType; import org.springframework.core.io.support.SpringFactoriesLoader; import org.springframework.messaging.Message; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * */ public class FunctionType { + /** + * Unclassified function types. + */ public static FunctionType UNCLASSIFIED = new FunctionType(ResolvableType .forClassWithGenerics(Function.class, Object.class, Object.class).getType()); @@ -61,34 +65,6 @@ public class FunctionType { this.message = messageType(); } - public Type getType() { - return type; - } - - public Class getInputWrapper() { - return inputWrapper; - } - - public Class getOutputWrapper() { - return outputWrapper; - } - - public Class getInputType() { - return inputType; - } - - public Class getOutputType() { - return outputType; - } - - public boolean isMessage() { - return message; - } - - public boolean isWrapper() { - return isWrapper(getInputWrapper()) || isWrapper(getOutputWrapper()); - } - public static boolean isWrapper(Type type) { if (type instanceof ParameterizedType) { type = ((ParameterizedType) type).getRawType(); @@ -125,6 +101,91 @@ public class FunctionType { ResolvableType.forClassWithGenerics(Consumer.class, input).getType()); } + public static FunctionType compose(FunctionType input, FunctionType output) { + ResolvableType inputGeneric = input(input); + ResolvableType outputGeneric = output(output); + if (!isWrapper(outputGeneric.getType())) { + ResolvableType inputOutput = output(input); + if (isWrapper(inputOutput.getType())) { + outputGeneric = wrap(input, + extractClass(inputOutput.getType(), ParamType.OUTPUT_WRAPPER), + extractClass(outputGeneric.getType(), ParamType.OUTPUT)); + } + } + return new FunctionType(ResolvableType + .forClassWithGenerics(Function.class, inputGeneric, outputGeneric) + .getType()); + } + + private static ResolvableType wrap(FunctionType input, Class wrapper, + Class type) { + return input.isMessage() ? wrap(wrapper, message(type)) + : ResolvableType.forClassWithGenerics(wrapper, type); + } + + private static ResolvableType wrap(Class wrapper, ResolvableType type) { + return ResolvableType.forClassWithGenerics(wrapper, type); + } + + private static ResolvableType message(Class type) { + return ResolvableType.forClassWithGenerics(Message.class, type); + } + + private static ResolvableType input(FunctionType type) { + return type.input(type.getInputType()); + } + + private static ResolvableType output(FunctionType type) { + return type.output(type.getOutputType()); + } + + private static Class extractClass(Type param, ParamType paramType) { + if (param instanceof ParameterizedType) { + ParameterizedType concrete = (ParameterizedType) param; + param = concrete.getRawType(); + } + if (param == null) { + // Last ditch attempt to guess: Flux + if (paramType.isWrapper()) { + param = Flux.class; + } + else { + param = String.class; + } + } + Class result = param instanceof Class ? (Class) param : null; + // TODO: cache result + return result; + } + + public Type getType() { + return this.type; + } + + public Class getInputWrapper() { + return this.inputWrapper; + } + + public Class getOutputWrapper() { + return this.outputWrapper; + } + + public Class getInputType() { + return this.inputType; + } + + public Class getOutputType() { + return this.outputType; + } + + public boolean isMessage() { + return this.message; + } + + public boolean isWrapper() { + return isWrapper(getInputWrapper()) || isWrapper(getOutputWrapper()); + } + public FunctionType to(Class output) { ResolvableType inputGeneric = input(this); ResolvableType outputGeneric = output(output); @@ -173,73 +234,69 @@ public class FunctionType { return wrap(wrapper, wrapper); } - public static FunctionType compose(FunctionType input, FunctionType output) { - ResolvableType inputGeneric = input(input); - ResolvableType outputGeneric = output(output); - if (!isWrapper(outputGeneric.getType())) { - ResolvableType inputOutput = output(input); - if (isWrapper(inputOutput.getType())) { - outputGeneric = wrap(input, - extractClass(inputOutput.getType(), ParamType.OUTPUT_WRAPPER), - extractClass(outputGeneric.getType(), ParamType.OUTPUT)); - } - } - return new FunctionType(ResolvableType - .forClassWithGenerics(Function.class, inputGeneric, outputGeneric) - .getType()); - } - @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result - + ((inputType == null) ? 0 : inputType.toString().hashCode()); + + ((this.inputType == null) ? 0 : this.inputType.toString().hashCode()); + result = prime * result + ((this.inputWrapper == null) ? 0 + : this.inputWrapper.toString().hashCode()); + result = prime * result + (this.message ? 1231 : 1237); result = prime * result - + ((inputWrapper == null) ? 0 : inputWrapper.toString().hashCode()); - result = prime * result + (message ? 1231 : 1237); - result = prime * result - + ((outputType == null) ? 0 : outputType.toString().hashCode()); - result = prime * result - + ((outputWrapper == null) ? 0 : outputWrapper.toString().hashCode()); + + ((this.outputType == null) ? 0 : this.outputType.toString().hashCode()); + result = prime * result + ((this.outputWrapper == null) ? 0 + : this.outputWrapper.toString().hashCode()); return result; } @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; - if (obj == null) + } + if (obj == null) { return false; - if (getClass() != obj.getClass()) + } + if (getClass() != obj.getClass()) { return false; + } FunctionType other = (FunctionType) obj; - if (inputType == null) { - if (other.inputType != null) + if (this.inputType == null) { + if (other.inputType != null) { return false; + } } - else if (!inputType.toString().equals(other.inputType.toString())) + else if (!this.inputType.toString().equals(other.inputType.toString())) { return false; - if (inputWrapper == null) { - if (other.inputWrapper != null) + } + if (this.inputWrapper == null) { + if (other.inputWrapper != null) { return false; + } } - else if (!inputWrapper.toString().equals(other.inputWrapper.toString())) + else if (!this.inputWrapper.toString().equals(other.inputWrapper.toString())) { return false; - if (message != other.message) + } + if (this.message != other.message) { return false; - if (outputType == null) { - if (other.outputType != null) + } + if (this.outputType == null) { + if (other.outputType != null) { return false; + } } - else if (!outputType.toString().equals(other.outputType.toString())) + else if (!this.outputType.toString().equals(other.outputType.toString())) { return false; - if (outputWrapper == null) { - if (other.outputWrapper != null) + } + if (this.outputWrapper == null) { + if (other.outputWrapper != null) { return false; + } } - else if (!outputWrapper.toString().equals(other.outputWrapper.toString())) + else if (!this.outputWrapper.toString().equals(other.outputWrapper.toString())) { return false; + } return true; } @@ -247,28 +304,6 @@ public class FunctionType { return wrap(this, wrapper, type); } - private static ResolvableType wrap(FunctionType input, Class wrapper, - Class type) { - return input.isMessage() ? wrap(wrapper, message(type)) - : ResolvableType.forClassWithGenerics(wrapper, type); - } - - private static ResolvableType wrap(Class wrapper, ResolvableType type) { - return ResolvableType.forClassWithGenerics(wrapper, type); - } - - private static ResolvableType message(Class type) { - return ResolvableType.forClassWithGenerics(Message.class, type); - } - - private static ResolvableType input(FunctionType type) { - return type.input(type.getInputType()); - } - - private static ResolvableType output(FunctionType type) { - return type.output(type.getOutputType()); - } - private ResolvableType output(Class type) { ResolvableType generic; ResolvableType raw = ResolvableType.forClass(type); @@ -331,25 +366,6 @@ public class FunctionType { return Object.class; } - private static Class extractClass(Type param, ParamType paramType) { - if (param instanceof ParameterizedType) { - ParameterizedType concrete = (ParameterizedType) param; - param = concrete.getRawType(); - } - if (param == null) { - // Last ditch attempt to guess: Flux - if (paramType.isWrapper()) { - param = Flux.class; - } - else { - param = String.class; - } - } - Class result = param instanceof Class ? (Class) param : null; - // TODO: cache result - return result; - } - private Type extractType(Type type, ParamType paramType, int index) { Type param; if (type instanceof ParameterizedType) { @@ -442,6 +458,7 @@ public class FunctionType { } enum ParamType { + INPUT, OUTPUT, INPUT_WRAPPER, OUTPUT_WRAPPER, INPUT_INNER_WRAPPER, OUTPUT_INNER_WRAPPER; public boolean isOutput() { @@ -460,6 +477,7 @@ public class FunctionType { public boolean isInnerWrapper() { return this == OUTPUT_INNER_WRAPPER || this == INPUT_INNER_WRAPPER; } + } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java index 7ebba189a..2ba28f465 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/FunctionalSpringApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.context; import java.util.Collections; @@ -39,11 +40,6 @@ import org.springframework.util.ClassUtils; public class FunctionalSpringApplication extends org.springframework.boot.SpringApplication { - /** - * Name of default property source. - */ - private static final String DEFAULT_PROPERTIES = "defaultProperties"; - /** * Flag to say that context is functional beans. */ @@ -54,6 +50,23 @@ public class FunctionalSpringApplication */ public static final String SPRING_WEB_APPLICATION_TYPE = "spring.main.web-application-type"; + /** + * Name of default property source. + */ + private static final String DEFAULT_PROPERTIES = "defaultProperties"; + + public FunctionalSpringApplication(Class... primarySources) { + super(primarySources); + setApplicationContextClass(GenericApplicationContext.class); + if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", + null)) { + setWebApplicationType(WebApplicationType.REACTIVE); + } + else { + setWebApplicationType(WebApplicationType.NONE); + } + } + public static void main(String[] args) throws Exception { FunctionalSpringApplication.run(new Class[0], args); } @@ -68,18 +81,6 @@ public class FunctionalSpringApplication return new FunctionalSpringApplication(primarySources).run(args); } - public FunctionalSpringApplication(Class... primarySources) { - super(primarySources); - setApplicationContextClass(GenericApplicationContext.class); - if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", - null)) { - setWebApplicationType(WebApplicationType.REACTIVE); - } - else { - setWebApplicationType(WebApplicationType.NONE); - } - } - @Override protected void postProcessApplicationContext(ConfigurableApplicationContext context) { super.postProcessApplicationContext(context); @@ -108,7 +109,7 @@ public class FunctionalSpringApplication handler = BeanUtils.instantiateClass(type); } @SuppressWarnings("unchecked") - ApplicationContextInitializer initializer = (ApplicationContextInitializer) handler; + ApplicationContextInitializer initializer = (ApplicationContextInitializer) handler; initializer.initialize(generic); functional = true; } @@ -118,8 +119,9 @@ public class FunctionalSpringApplication Class functionType = type; Object function = handler; generic.registerBean("function", FunctionRegistration.class, - () -> new FunctionRegistration<>(handler(generic, function, functionType)) - .type(FunctionType.of(functionType))); + () -> new FunctionRegistration<>( + handler(generic, function, functionType)) + .type(FunctionType.of(functionType))); functional = true; } } @@ -130,7 +132,8 @@ public class FunctionalSpringApplication } } - private Object handler(GenericApplicationContext generic, Object handler, Class type) { + private Object handler(GenericApplicationContext generic, Object handler, + Class type) { if (handler == null) { handler = generic.getAutowireCapableBeanFactory().createBean(type); } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/WrapperDetector.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/WrapperDetector.java index 419c94d4e..f242276df 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/WrapperDetector.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/WrapperDetector.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionCatalogEvent.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionCatalogEvent.java index 2aeff2d71..c17f03239 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionCatalogEvent.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionCatalogEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.context.catalog; import org.springframework.context.ApplicationEvent; diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java index 7aa4187a5..9dc5c04b8 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionInspector.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionRegistrationEvent.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionRegistrationEvent.java index 0d3cb1360..f78d6710a 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionRegistrationEvent.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionRegistrationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.context.catalog; import java.util.HashSet; @@ -26,6 +27,7 @@ import java.util.Set; public class FunctionRegistrationEvent extends FunctionCatalogEvent { private final Class type; + private final Set names; public FunctionRegistrationEvent(Object source, Class type, Set names) { @@ -35,11 +37,11 @@ public class FunctionRegistrationEvent extends FunctionCatalogEvent { } public Class getType() { - return type; + return this.type; } public Set getNames() { - return names; + return this.names; } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionUnregistrationEvent.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionUnregistrationEvent.java index dec1b3fa3..35aa32b52 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionUnregistrationEvent.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/FunctionUnregistrationEvent.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.context.catalog; import java.util.HashSet; @@ -26,6 +27,7 @@ import java.util.Set; public class FunctionUnregistrationEvent extends FunctionCatalogEvent { private final Class type; + private final Set names; public FunctionUnregistrationEvent(Object source, Class type, Set names) { @@ -35,11 +37,11 @@ public class FunctionUnregistrationEvent extends FunctionCatalogEvent { } public Class getType() { - return type; + return this.type; } public Set getNames() { - return names; + return this.names; } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java index df4d84c43..06653c667 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalog.java @@ -1,11 +1,11 @@ /* - * Copyright 2016-2019 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -81,16 +81,17 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry FunctionRegistrationEvent event = new FunctionRegistrationEvent(this, type, registration.getNames()); - registrations.put(registration.getTarget(), registration); + this.registrations.put(registration.getTarget(), registration); FunctionRegistration wrapped = registration.wrap(); if (wrapped != registration) { registration = wrapped; - registrations.put(wrapped.getTarget(), wrapped); + this.registrations.put(wrapped.getTarget(), wrapped); if (type == Consumer.class) { type = Function.class; } } - Map map = functions.computeIfAbsent(type, key -> new HashMap<>()); + Map map = this.functions.computeIfAbsent(type, + key -> new HashMap<>()); for (String name : registration.getNames()) { map.put(name, registration.getTarget()); } @@ -104,19 +105,19 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry @PostConstruct public void init() { - if (publisher != null && !functions.isEmpty()) { - functions.keySet() + if (this.publisher != null && !this.functions.isEmpty()) { + this.functions.keySet() .forEach(type -> this.publishEvent(new FunctionRegistrationEvent(this, - type, functions.get(type).keySet()))); + type, this.functions.get(type).keySet()))); } } @PreDestroy public void close() { - if (publisher != null && !functions.isEmpty()) { - functions.keySet().forEach( + if (this.publisher != null && !this.functions.isEmpty()) { + this.functions.keySet().forEach( type -> this.publishEvent(new FunctionUnregistrationEvent(this, type, - functions.get(type).keySet()))); + this.functions.get(type).keySet()))); } } @@ -125,7 +126,7 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry public T doLookup(Class type, String name) { T function = null; if (type == null) { - function = (T) functions.values().stream() + function = (T) this.functions.values().stream() .filter(map -> map.get(name) != null).map(map -> map.get(name)) .findFirst().orElse(null); } @@ -138,7 +139,7 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry @Override public Set getNames(Class type) { if (type == null) { - return functions.values().stream().flatMap(map -> map.keySet().stream()) + return this.functions.values().stream().flatMap(map -> map.keySet().stream()) .collect(Collectors.toSet()); } Map map = this.extractTypeMap(type); @@ -146,10 +147,10 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry } private Map extractTypeMap(Class type) { - return functions.keySet().stream() + return this.functions.keySet().stream() .filter(key -> key != Object.class && key.isAssignableFrom(type)) - .map(key -> functions.get(key)).findFirst() - .orElse(functions.get(Object.class)); + .map(key -> this.functions.get(key)).findFirst() + .orElse(this.functions.get(Object.class)); } private void publishEvent(Object event) { @@ -157,4 +158,5 @@ public class InMemoryFunctionCatalog extends AbstractFunctionRegistry this.publisher.publishEvent(event); } } + } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java index 6add1ec69..217e754bf 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfiguration.java @@ -1,11 +1,11 @@ /* - * Copyright 2016-2019 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -32,6 +32,11 @@ import java.util.stream.Stream; import javax.annotation.PreDestroy; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.gson.Gson; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanDefinition; @@ -62,22 +67,16 @@ import org.springframework.cloud.function.json.JacksonMapper; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; -import org.springframework.context.annotation.ComponentScan.Filter; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.type.StandardMethodMetadata; import org.springframework.stereotype.Component; import org.springframework.util.Assert; import org.springframework.util.StringUtils; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.google.gson.Gson; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @author Mark Fisher @@ -86,8 +85,10 @@ import reactor.core.publisher.Mono; */ @Configuration @ConditionalOnMissingBean(FunctionCatalog.class) -@ComponentScan(basePackages = "${spring.cloud.function.scan.packages:functions}", - includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = {Supplier.class, Function.class, Consumer.class})) +// @checkstyle:off +@ComponentScan(basePackages = "${spring.cloud.function.scan.packages:functions}", includeFilters = @Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { + Supplier.class, Function.class, Consumer.class })) +// @checkstyle:on public class ContextFunctionCatalogAutoConfiguration { static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper"; @@ -104,11 +105,10 @@ public class ContextFunctionCatalogAutoConfiguration { @Autowired(required = false) private Map> registrations = Collections.emptyMap(); - - @Bean public FunctionRegistry functionCatalog(ContextFunctionRegistry processor) { - processor.merge(registrations, consumers, suppliers, functions); + processor.merge(this.registrations, this.consumers, this.suppliers, + this.functions); return new BeanFactoryFunctionCatalog(processor); } @@ -121,11 +121,15 @@ public class ContextFunctionCatalogAutoConfiguration { private final ContextFunctionRegistry processor; + public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) { + this.processor = processor; + } + @Override public void register(FunctionRegistration registration) { Assert.notEmpty(registration.getNames(), "'registration' must contain at least one name before it is registered in catalog."); - processor.register(registration); + this.processor.register(registration); } @Override @@ -133,22 +137,22 @@ public class ContextFunctionCatalogAutoConfiguration { protected T doLookup(Class type, String name) { T function = null; if (type == null) { - function = (T) processor.lookupFunction(name); + function = (T) this.processor.lookupFunction(name); if (function == null) { - function = (T) processor.lookupConsumer(name); + function = (T) this.processor.lookupConsumer(name); } if (function == null) { - function = (T) processor.lookupSupplier(name); + function = (T) this.processor.lookupSupplier(name); } } else if (Supplier.class.isAssignableFrom(type)) { - function = (T) processor.lookupSupplier(name); + function = (T) this.processor.lookupSupplier(name); } else if (Consumer.class.isAssignableFrom(type)) { - function = (T) processor.lookupConsumer(name); + function = (T) this.processor.lookupConsumer(name); } else if (Function.class.isAssignableFrom(type)) { - function = (T) processor.lookupFunction(name); + function = (T) this.processor.lookupFunction(name); } return function; } @@ -174,26 +178,6 @@ public class ContextFunctionCatalogAutoConfiguration { + this.processor.getConsumers().size(); } - public BeanFactoryFunctionCatalog(ContextFunctionRegistry processor) { - this.processor = processor; - } - - } - - protected class BeanFactoryFunctionInspector implements FunctionInspector { - - private ContextFunctionRegistry processor; - - public BeanFactoryFunctionInspector(ContextFunctionRegistry processor) { - this.processor = processor; - } - - @Override - public FunctionRegistration getRegistration(Object function) { - FunctionRegistration registration = processor.getRegistration(function); - return registration; - } - } @Configuration @@ -201,21 +185,27 @@ public class ContextFunctionCatalogAutoConfiguration { @ConditionalOnBean(Gson.class) @Conditional(PreferGsonOrMissingJacksonCondition.class) protected static class GsonConfiguration { + @Bean public GsonMapper jsonMapper(Gson gson) { return new GsonMapper(gson); } + } @Configuration @ConditionalOnClass(ObjectMapper.class) @ConditionalOnBean(ObjectMapper.class) + // @checkstyle:off @ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "jackson", matchIfMissing = true) + // @checkstyle:on protected static class JacksonConfiguration { + @Bean public JacksonMapper jsonMapper(ObjectMapper mapper) { return new JacksonMapper(mapper); } + } @Component @@ -242,10 +232,10 @@ public class ContextFunctionCatalogAutoConfiguration { } public FunctionRegistration getRegistration(Object function) { - if (function == null || !names.containsKey(function)) { + if (function == null || !this.names.containsKey(function)) { return null; } - return new FunctionRegistration<>(function, names.get(function)) + return new FunctionRegistration<>(function, this.names.get(function)) .type(findType(function).getType()); } @@ -315,15 +305,15 @@ public class ContextFunctionCatalogAutoConfiguration { } final Object value = function; lookup.computeIfAbsent(name, key -> value); - if (!types.containsKey(name)) { - if (types.containsKey(stages[0]) - && types.containsKey(stages[stages.length - 1])) { - FunctionType input = types.get(stages[0]); - FunctionType output = types.get(stages[stages.length - 1]); - types.put(name, FunctionType.compose(input, output)); + if (!this.types.containsKey(name)) { + if (this.types.containsKey(stages[0]) + && this.types.containsKey(stages[stages.length - 1])) { + FunctionType input = this.types.get(stages[0]); + FunctionType output = this.types.get(stages[stages.length - 1]); + this.types.put(name, FunctionType.compose(input, output)); } } - names.put(function, name); + this.names.put(function, name); return function; } @@ -341,12 +331,14 @@ public class ContextFunctionCatalogAutoConfiguration { Supplier> supplier = (Supplier>) a; if (b instanceof FluxConsumer) { if (supplier instanceof FluxSupplier) { - FluxConsumer fConsumer = ((FluxConsumer)b); - return (Supplier>) () -> Mono.from(supplier.get().compose(v -> fConsumer.apply(supplier.get()))); + FluxConsumer fConsumer = ((FluxConsumer) b); + return (Supplier>) () -> Mono.from(supplier.get() + .compose(v -> fConsumer.apply(supplier.get()))); } else { - throw new IllegalStateException("The provided supplier is finite (i.e., already composed with Consumer) " - + "therefore it can not be composed with another consumer"); + throw new IllegalStateException( + "The provided supplier is finite (i.e., already composed with Consumer) " + + "therefore it can not be composed with another consumer"); } } else { @@ -362,13 +354,16 @@ public class ContextFunctionCatalogAutoConfiguration { return function1.andThen(function2); } else { - throw new IllegalStateException("The provided function is finite (i.e., returns Mono) " - + "therefore it can *only* be composed with compatible function (i.e., Function"); + throw new IllegalStateException( + "The provided function is finite (i.e., returns Mono) " + + "therefore it can *only* be composed with compatible function (i.e., Function"); } } else if (function2 instanceof FluxToMonoFunction) { - return new FluxToMonoFunction(((Function, Flux>)a) - .andThen(((FluxToMonoFunction) b).getTarget())); + return new FluxToMonoFunction( + ((Function, Flux>) a) + .andThen(((FluxToMonoFunction) b) + .getTarget())); } else { return function1.andThen(function2); @@ -391,18 +386,18 @@ public class ContextFunctionCatalogAutoConfiguration { @PreDestroy public void close() { - if (publisher != null) { - if (!functions.isEmpty()) { - publisher.publishEvent(new FunctionUnregistrationEvent(this, - Function.class, functions.keySet())); + if (this.publisher != null) { + if (!this.functions.isEmpty()) { + this.publisher.publishEvent(new FunctionUnregistrationEvent(this, + Function.class, this.functions.keySet())); } - if (!consumers.isEmpty()) { - publisher.publishEvent(new FunctionUnregistrationEvent(this, - Consumer.class, consumers.keySet())); + if (!this.consumers.isEmpty()) { + this.publisher.publishEvent(new FunctionUnregistrationEvent(this, + Consumer.class, this.consumers.keySet())); } - if (!suppliers.isEmpty()) { - publisher.publishEvent(new FunctionUnregistrationEvent(this, - Supplier.class, suppliers.keySet())); + if (!this.suppliers.isEmpty()) { + this.publisher.publishEvent(new FunctionUnregistrationEvent(this, + Supplier.class, this.suppliers.keySet())); } } } @@ -443,8 +438,8 @@ public class ContextFunctionCatalogAutoConfiguration { private Collection getAliases(String key) { Collection names = new LinkedHashSet<>(); String value = getQualifier(key); - if (value.equals(key) && registry != null) { - names.addAll(Arrays.asList(registry.getAliases(key))); + if (value.equals(key) && this.registry != null) { + names.addAll(Arrays.asList(this.registry.getAliases(key))); } names.add(value); return names; @@ -485,8 +480,8 @@ public class ContextFunctionCatalogAutoConfiguration { } // this.names.remove(target); this.names.put(registration.getTarget(), key); - if (publisher != null) { - publisher.publishEvent(new FunctionRegistrationEvent( + if (this.publisher != null) { + this.publisher.publishEvent(new FunctionRegistrationEvent( registration.getTarget(), type, registration.getNames())); } } @@ -552,8 +547,8 @@ public class ContextFunctionCatalogAutoConfiguration { } private String getQualifier(String key) { - if (registry != null && registry.containsBeanDefinition(key)) { - BeanDefinition beanDefinition = registry.getBeanDefinition(key); + if (this.registry != null && this.registry.containsBeanDefinition(key)) { + BeanDefinition beanDefinition = this.registry.getBeanDefinition(key); Object source = beanDefinition.getSource(); if (source instanceof StandardMethodMetadata) { StandardMethodMetadata metadata = (StandardMethodMetadata) source; @@ -568,13 +563,13 @@ public class ContextFunctionCatalogAutoConfiguration { } private FunctionType findType(Object function) { - String name = names.get(function); - if (types.containsKey(name)) { - return types.get(name); + String name = this.names.get(function); + if (this.types.containsKey(name)) { + return this.types.get(name); } FunctionType param; - if (name == null || registry == null - || !registry.containsBeanDefinition(name)) { + if (name == null || this.registry == null + || !this.registry.containsBeanDefinition(name)) { if (function != null) { param = new FunctionType(function.getClass()); } @@ -583,9 +578,10 @@ public class ContextFunctionCatalogAutoConfiguration { } } else { - param = new FunctionType(FunctionContextUtils.findType(name, registry)); + param = new FunctionType( + FunctionContextUtils.findType(name, this.registry)); } - types.computeIfAbsent(name, str -> param); + this.types.computeIfAbsent(name, str -> param); return param; } @@ -597,7 +593,7 @@ public class ContextFunctionCatalogAutoConfiguration { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnProperty(name = ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false) + @ConditionalOnProperty(name = PREFERRED_MAPPER_PROPERTY, havingValue = "gson", matchIfMissing = false) static class GsonPreferred { } @@ -609,4 +605,21 @@ public class ContextFunctionCatalogAutoConfiguration { } + protected class BeanFactoryFunctionInspector implements FunctionInspector { + + private ContextFunctionRegistry processor; + + public BeanFactoryFunctionInspector(ContextFunctionRegistry processor) { + this.processor = processor; + } + + @Override + public FunctionRegistration getRegistration(Object function) { + FunctionRegistration registration = this.processor + .getRegistration(function); + return registration; + } + + } + } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java index a92d567fc..89650fcac 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -50,8 +50,14 @@ import org.springframework.util.ClassUtils; public class ContextFunctionCatalogInitializer implements ApplicationContextInitializer { + /** + * Property name for ignoring pre initilizer. + */ public static final String IGNORE_BACKGROUNDPREINITIALIZER_PROPERTY_NAME = "spring.backgroundpreinitializer.ignore"; + /** + * Flag for enabling the context function catalog initializer. + */ public static boolean enabled = true; @Override @@ -69,7 +75,7 @@ public class ContextFunctionCatalogInitializer private GenericApplicationContext context; - public ContextFunctionCatalogBeanRegistrar( + ContextFunctionCatalogBeanRegistrar( GenericApplicationContext applicationContext) { this.context = applicationContext; } @@ -101,65 +107,67 @@ public class ContextFunctionCatalogInitializer performPreinitialization(); - if (context.getBeanFactory().getBeanNamesForType( + if (this.context.getBeanFactory().getBeanNamesForType( PropertySourcesPlaceholderConfigurer.class, false, false).length == 0) { - context.registerBean(PropertySourcesPlaceholderConfigurer.class, + this.context.registerBean(PropertySourcesPlaceholderConfigurer.class, () -> PropertyPlaceholderAutoConfiguration .propertySourcesPlaceholderConfigurer()); } - if (!context.getBeanFactory().containsBean( + if (!this.context.getBeanFactory().containsBean( AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) { // Switch off the ConfigurationClassPostProcessor - context.registerBean( + this.context.registerBean( AnnotationConfigUtils.CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME, DummyProcessor.class, () -> new DummyProcessor()); // But switch on other annotation processing - AnnotationConfigUtils.registerAnnotationConfigProcessors(context); + AnnotationConfigUtils.registerAnnotationConfigProcessors(this.context); } - if (!context.getBeanFactory() + if (!this.context.getBeanFactory() .containsBean(ConfigurationBeanFactoryMetadata.BEAN_NAME)) { - context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, + this.context.registerBean(ConfigurationBeanFactoryMetadata.BEAN_NAME, ConfigurationBeanFactoryMetadata.class, () -> new ConfigurationBeanFactoryMetadata()); - context.registerBean( + this.context.registerBean( ConfigurationPropertiesBindingPostProcessor.BEAN_NAME, ConfigurationPropertiesBindingPostProcessor.class, () -> new ConfigurationPropertiesBindingPostProcessor()); } if (ClassUtils.isPresent("com.google.gson.Gson", null) - && "gson".equals(context.getEnvironment().getProperty( + && "gson".equals(this.context.getEnvironment().getProperty( ContextFunctionCatalogAutoConfiguration.PREFERRED_MAPPER_PROPERTY, "gson"))) { - if (context.getBeanFactory().getBeanNamesForType(Gson.class, false, + if (this.context.getBeanFactory().getBeanNamesForType(Gson.class, false, false).length == 0) { - context.registerBean(Gson.class, () -> new Gson()); + this.context.registerBean(Gson.class, () -> new Gson()); } - context.registerBean(JsonMapper.class, + this.context.registerBean(JsonMapper.class, () -> new ContextFunctionCatalogAutoConfiguration.GsonConfiguration() - .jsonMapper(context.getBean(Gson.class))); + .jsonMapper(this.context.getBean(Gson.class))); } else if (ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", null)) { - if (context.getBeanFactory().getBeanNamesForType(ObjectMapper.class, + if (this.context.getBeanFactory().getBeanNamesForType(ObjectMapper.class, false, false).length == 0) { - context.registerBean(ObjectMapper.class, () -> new ObjectMapper()); + this.context.registerBean(ObjectMapper.class, + () -> new ObjectMapper()); } - context.registerBean(JsonMapper.class, + this.context.registerBean(JsonMapper.class, () -> new ContextFunctionCatalogAutoConfiguration.JacksonConfiguration() - .jsonMapper(context.getBean(ObjectMapper.class))); + .jsonMapper(this.context.getBean(ObjectMapper.class))); } - if (context.getBeanFactory().getBeanNamesForType(FunctionCatalog.class, false, - false).length == 0) { - context.registerBean(InMemoryFunctionCatalog.class, + if (this.context.getBeanFactory().getBeanNamesForType(FunctionCatalog.class, + false, false).length == 0) { + this.context.registerBean(InMemoryFunctionCatalog.class, () -> new InMemoryFunctionCatalog()); - context.registerBean(FunctionRegistrationPostProcessor.class, - () -> new FunctionRegistrationPostProcessor( - context.getAutowireCapableBeanFactory() + this.context + .registerBean(FunctionRegistrationPostProcessor.class, + () -> new FunctionRegistrationPostProcessor(this.context + .getAutowireCapableBeanFactory() .getBeanProvider(FunctionRegistration.class))); } } @@ -193,10 +201,11 @@ public class ContextFunctionCatalogInitializer } private class FunctionRegistrationPostProcessor implements BeanPostProcessor { + @SuppressWarnings("rawtypes") private final ObjectProvider functions; - public FunctionRegistrationPostProcessor( + FunctionRegistrationPostProcessor( @SuppressWarnings("rawtypes") ObjectProvider functions) { this.functions = functions; } @@ -206,7 +215,7 @@ public class ContextFunctionCatalogInitializer throws BeansException { if (bean instanceof FunctionRegistry) { FunctionRegistry catalog = (FunctionRegistry) bean; - for (FunctionRegistration registration : functions) { + for (FunctionRegistration registration : this.functions) { Assert.notEmpty(registration.getNames(), "FunctionRegistration must define at least one name. Was empty"); if (registration.getType() == null) { @@ -222,13 +231,19 @@ public class ContextFunctionCatalogInitializer } return bean; } + } } + /** + * Dummy implementation of a processor. + */ public static class DummyProcessor { + public void setMetadataReaderFactory(MetadataReaderFactory obj) { } + } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FluxWrapperDetector.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FluxWrapperDetector.java index 1291a1c12..7c5ba995e 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FluxWrapperDetector.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FluxWrapperDetector.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java index 52d58f3f2..aad4d043b 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/config/FunctionContextUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -38,103 +38,106 @@ import org.springframework.util.ReflectionUtils; /** * @author Oleg Zhurakousky - * * @since 2.0 */ abstract class FunctionContextUtils { - public static Type findType(String name, ConfigurableListableBeanFactory registry) { - AbstractBeanDefinition definition = (AbstractBeanDefinition) registry.getBeanDefinition(name); - Object source = definition.getSource(); - Type param = null; - // Start by assuming output -> Function - if (source instanceof StandardMethodMetadata) { - // Standard @Bean metadata - param = ((StandardMethodMetadata) source).getIntrospectedMethod() - .getGenericReturnType(); - } - else if (source instanceof MethodMetadataReadingVisitor) { - // A component scan with @Beans - MethodMetadataReadingVisitor visitor = (MethodMetadataReadingVisitor) source; - param = findBeanType(definition, visitor); - } - else if (source instanceof Resource) { - param = registry.getType(name); - } - else { - ResolvableType type = (ResolvableType) getField(definition, "targetType"); - if (type != null) { - param = type.getType(); - } - else { - Class beanClass = definition.getBeanClass(); - if (beanClass != null && !FunctionFactoryMetadata.class.isAssignableFrom(beanClass)) { - param = beanClass; - } - else { - //assume FunctionFactoryMetadata - FunctionFactoryMetadata factory = (FunctionFactoryMetadata) registry.getBean(name); - param = factory.getFactoryMethod().getGenericReturnType(); - } - } - } - return param; - } + public static Type findType(String name, ConfigurableListableBeanFactory registry) { + AbstractBeanDefinition definition = (AbstractBeanDefinition) registry + .getBeanDefinition(name); + Object source = definition.getSource(); + Type param = null; + // Start by assuming output -> Function + if (source instanceof StandardMethodMetadata) { + // Standard @Bean metadata + param = ((StandardMethodMetadata) source).getIntrospectedMethod() + .getGenericReturnType(); + } + else if (source instanceof MethodMetadataReadingVisitor) { + // A component scan with @Beans + MethodMetadataReadingVisitor visitor = (MethodMetadataReadingVisitor) source; + param = findBeanType(definition, visitor); + } + else if (source instanceof Resource) { + param = registry.getType(name); + } + else { + ResolvableType type = (ResolvableType) getField(definition, "targetType"); + if (type != null) { + param = type.getType(); + } + else { + Class beanClass = definition.getBeanClass(); + if (beanClass != null + && !FunctionFactoryMetadata.class.isAssignableFrom(beanClass)) { + param = beanClass; + } + else { + // assume FunctionFactoryMetadata + FunctionFactoryMetadata factory = (FunctionFactoryMetadata) registry + .getBean(name); + param = factory.getFactoryMethod().getGenericReturnType(); + } + } + } + return param; + } - private static Type findBeanType(AbstractBeanDefinition definition, - MethodMetadataReadingVisitor visitor) { - Class factory = ClassUtils - .resolveClassName(visitor.getDeclaringClassName(), null); - Class[] params = getParamTypes(factory, definition); - Method method = ReflectionUtils.findMethod(factory, visitor.getMethodName(), - params); - Type type = method.getGenericReturnType(); - return type; - } + private static Type findBeanType(AbstractBeanDefinition definition, + MethodMetadataReadingVisitor visitor) { + Class factory = ClassUtils.resolveClassName(visitor.getDeclaringClassName(), + null); + Class[] params = getParamTypes(factory, definition); + Method method = ReflectionUtils.findMethod(factory, visitor.getMethodName(), + params); + Type type = method.getGenericReturnType(); + return type; + } - private static Class[] getParamTypes(Class factory, - AbstractBeanDefinition definition) { - if (definition instanceof RootBeanDefinition) { - RootBeanDefinition root = (RootBeanDefinition) definition; - for (Method method : getCandidateMethods(factory, root)) { - if (root.isFactoryMethod(method)) { - return method.getParameterTypes(); - } - } - } - List> params = new ArrayList<>(); - for (ConstructorArgumentValues.ValueHolder holder : definition.getConstructorArgumentValues() - .getIndexedArgumentValues().values()) { - params.add(ClassUtils.resolveClassName(holder.getType(), null)); - } - return params.toArray(new Class[0]); - } + private static Class[] getParamTypes(Class factory, + AbstractBeanDefinition definition) { + if (definition instanceof RootBeanDefinition) { + RootBeanDefinition root = (RootBeanDefinition) definition; + for (Method method : getCandidateMethods(factory, root)) { + if (root.isFactoryMethod(method)) { + return method.getParameterTypes(); + } + } + } + List> params = new ArrayList<>(); + for (ConstructorArgumentValues.ValueHolder holder : definition + .getConstructorArgumentValues().getIndexedArgumentValues().values()) { + params.add(ClassUtils.resolveClassName(holder.getType(), null)); + } + return params.toArray(new Class[0]); + } - private static Method[] getCandidateMethods(final Class factoryClass, - final RootBeanDefinition mbd) { - if (System.getSecurityManager() != null) { - return AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Method[] run() { - return (mbd.isNonPublicAccessAllowed() - ? ReflectionUtils.getAllDeclaredMethods(factoryClass) - : factoryClass.getMethods()); - } - }); - } - else { - return (mbd.isNonPublicAccessAllowed() - ? ReflectionUtils.getAllDeclaredMethods(factoryClass) - : factoryClass.getMethods()); - } - } + private static Method[] getCandidateMethods(final Class factoryClass, + final RootBeanDefinition mbd) { + if (System.getSecurityManager() != null) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Method[] run() { + return (mbd.isNonPublicAccessAllowed() + ? ReflectionUtils.getAllDeclaredMethods(factoryClass) + : factoryClass.getMethods()); + } + }); + } + else { + return (mbd.isNonPublicAccessAllowed() + ? ReflectionUtils.getAllDeclaredMethods(factoryClass) + : factoryClass.getMethods()); + } + } + + private static Object getField(Object target, String name) { + Field field = ReflectionUtils.findField(target.getClass(), name); + if (field == null) { + return null; + } + ReflectionUtils.makeAccessible(field); + return ReflectionUtils.getField(field, target); + } - private static Object getField(Object target, String name) { - Field field = ReflectionUtils.findField(target.getClass(), name); - if (field == null) { - return null; - } - ReflectionUtils.makeAccessible(field); - return ReflectionUtils.getField(field, target); - } } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/message/MessageUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/message/MessageUtils.java index 1174592d2..3ccaf384c 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/message/MessageUtils.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/message/MessageUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -39,7 +39,6 @@ public abstract class MessageUtils { * isolated class loader, then the message will be created with the target class * loader (therefore the {@link Message} class must be on the classpath of the target * class loader). - * * @param handler the function that will be applied to the message * @param payload the payload of the message * @param headers the headers for the message @@ -74,7 +73,6 @@ public abstract class MessageUtils { * class loader. If the handler is a wrapper for a function in an isolated class * loader, then the message will be created with the target class loader (therefore * the {@link Message} class must be on the classpath of the target class loader). - * * @param handler the function that generated the message * @param message the message to convert * @return a message with the correct class loader diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalSpringBootTest.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalSpringBootTest.java index 847846588..8a45231fb 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalSpringBootTest.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalSpringBootTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -42,16 +42,16 @@ import org.springframework.test.context.ContextConfiguration; @ContextConfiguration(loader = FunctionalTestContextLoader.class) public @interface FunctionalSpringBootTest { - @AliasFor(annotation=SpringBootTest.class, attribute="properties") + @AliasFor(annotation = SpringBootTest.class, attribute = "properties") String[] value() default {}; - @AliasFor(annotation=SpringBootTest.class, attribute="value") + @AliasFor(annotation = SpringBootTest.class, attribute = "value") String[] properties() default {}; - @AliasFor(annotation=SpringBootTest.class, attribute="classes") + @AliasFor(annotation = SpringBootTest.class, attribute = "classes") Class[] classes() default {}; - @AliasFor(annotation=SpringBootTest.class, attribute="webEnvironment") + @AliasFor(annotation = SpringBootTest.class, attribute = "webEnvironment") WebEnvironment webEnvironment() default WebEnvironment.MOCK; } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalTestContextLoader.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalTestContextLoader.java index b6a562340..b6c6ccfa3 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalTestContextLoader.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/context/test/FunctionalTestContextLoader.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -34,4 +34,5 @@ class FunctionalTestContextLoader extends SpringBootContextLoader { protected SpringApplication getSpringApplication() { return new FunctionalSpringApplication(); } + } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/GsonMapper.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/GsonMapper.java index c46a5df82..647b5cd54 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/GsonMapper.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/GsonMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.json; import java.lang.reflect.Type; @@ -34,11 +35,12 @@ public class GsonMapper implements JsonMapper { @Override public T toObject(String json, Type type) { - return gson.fromJson(json, type); + return this.gson.fromJson(json, type); } @Override public String toString(Object value) { - return gson.toJson(value); + return this.gson.toJson(value); } + } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JacksonMapper.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JacksonMapper.java index 4bcff9987..ab2a1efb7 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JacksonMapper.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JacksonMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.json; import java.lang.reflect.Type; @@ -36,7 +37,8 @@ public class JacksonMapper implements JsonMapper { @Override public T toObject(String json, Type type) { try { - return mapper.readValue(json, TypeFactory.defaultInstance().constructType(type)); + return this.mapper.readValue(json, + TypeFactory.defaultInstance().constructType(type)); } catch (Exception e) { throw new IllegalArgumentException("Cannot convert JSON " + json, e); @@ -46,10 +48,11 @@ public class JacksonMapper implements JsonMapper { @Override public String toString(Object value) { try { - return mapper.writeValueAsString(value); + return this.mapper.writeValueAsString(value); } catch (JsonProcessingException e) { throw new IllegalArgumentException("Cannot convert to JSON", e); } } + } diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JsonMapper.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JsonMapper.java index 15ffa3574..6719a10f0 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JsonMapper.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/json/JsonMapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.json; import java.lang.reflect.Type; @@ -28,6 +29,10 @@ import org.springframework.core.ResolvableType; public interface JsonMapper { /** + * @param type for list arguments + * @param json JSON input + * @param type type of list arguments + * @return list of elements * @deprecated since v2.0 in favor of {@link #toObject(String, Type)} */ @Deprecated @@ -40,11 +45,19 @@ public interface JsonMapper { } /** + * @param return type + * @param json JSON input + * @param type type + * @return object * @since 2.0 */ T toObject(String json, Type type); /** + * @param type for list arguments + * @param json JSON input + * @param type type of list arguments + * @return single object * @deprecated since v2.0 in favor of {@link #toObject(String, Type)} */ default T toSingle(String json, Class type) { diff --git a/spring-cloud-function-context/src/main/resources/META-INF/spring-configuration-metadata.json b/spring-cloud-function-context/src/main/resources/META-INF/spring-configuration-metadata.json index 243510875..7a5ce76a5 100644 --- a/spring-cloud-function-context/src/main/resources/META-INF/spring-configuration-metadata.json +++ b/spring-cloud-function-context/src/main/resources/META-INF/spring-configuration-metadata.json @@ -1,18 +1,18 @@ { - "hints": [], - "groups": [], - "properties": [ - { - "name": "spring.cloud.function.scan.packages", - "type": "java.lang.String", - "description": "Triggers scanning within the specified base packages for any class that is assignable to java.util.function.Function. For each detected Function class, a bean instance will be added to the context.", - "defaultValue": "functions" - }, - { - "name": "spring.cloud.function.definition", - "type": "java.lang.String", - "description": "Name (e.g., 'foo') or composition instruction (e.g., 'foo|bar') used to resolve default function especially for cases where there is more then once function available in catalog.", - "defaultValue": "" - } - ] -} \ No newline at end of file + "hints": [], + "groups": [], + "properties": [ + { + "name": "spring.cloud.function.scan.packages", + "type": "java.lang.String", + "description": "Triggers scanning within the specified base packages for any class that is assignable to java.util.function.Function. For each detected Function class, a bean instance will be added to the context.", + "defaultValue": "functions" + }, + { + "name": "spring.cloud.function.definition", + "type": "java.lang.String", + "description": "Name (e.g., 'foo') or composition instruction (e.g., 'foo|bar') used to resolve default function especially for cases where there is more then once function available in catalog.", + "defaultValue": "" + } + ] +} diff --git a/spring-cloud-function-context/src/main/resources/META-INF/spring.factories b/spring-cloud-function-context/src/main/resources/META-INF/spring.factories index aa9a9c745..1dbbeee8d 100644 --- a/spring-cloud-function-context/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-function-context/src/main/resources/META-INF/spring.factories @@ -1,8 +1,6 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration - org.springframework.cloud.function.context.WrapperDetector=\ org.springframework.cloud.function.context.config.FluxWrapperDetector - org.springframework.context.ApplicationContextInitializer=\ -org.springframework.cloud.function.context.config.ContextFunctionCatalogInitializer \ No newline at end of file +org.springframework.cloud.function.context.config.ContextFunctionCatalogInitializer diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionRegistrationTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionRegistrationTests.java index cf30ca2ef..32176ce7a 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionRegistrationTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionRegistrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -46,10 +46,12 @@ public class FunctionRegistrationTests { } private static class Foos implements Function { + @Override public String apply(Integer t) { return "i=" + t; } + } } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java index 5f0411788..85fe0e59a 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/FunctionTypeTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,6 +23,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.junit.Test; +import reactor.core.publisher.Flux; import org.springframework.core.ResolvableType; import org.springframework.messaging.Message; @@ -30,8 +31,6 @@ import org.springframework.messaging.support.MessageBuilder; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -50,7 +49,8 @@ public class FunctionTypeTests { @Test public void supplierOfRegistration() { - FunctionType function = new FunctionType(SupplierOfRegistrationOfIntegerToString.class); + FunctionType function = new FunctionType( + SupplierOfRegistrationOfIntegerToString.class); assertThat(function.getInputType()).isEqualTo(Integer.class); assertThat(function.getOutputType()).isEqualTo(String.class); assertThat(function.getInputWrapper()).isEqualTo(Integer.class); @@ -247,60 +247,80 @@ public class FunctionTypeTests { assertThat(function).isSameAs(function.wrap(Object.class)); } - private static class SupplierOfRegistrationOfIntegerToString implements Supplier>> { + private static class SupplierOfRegistrationOfIntegerToString + implements Supplier>> { + @Override public FunctionRegistration> get() { - return new FunctionRegistration>(new IntegerToString(), "ints"); + return new FunctionRegistration>( + new IntegerToString(), "ints"); } + } - - private static class SupplierOfIntegerToString implements Supplier> { + + private static class SupplierOfIntegerToString + implements Supplier> { + @Override public Function get() { return new IntegerToString(); } + } - + private static class IntegerToString implements Function { + @Override public String apply(Integer t) { return "" + t; } + } private static class StringToMap implements Function> { + @Override public Map apply(String t) { return Collections.emptyMap(); } + } private static class FooToFoo implements Function { + @Override public Bar apply(Foo t) { return new Bar(); } + } private static class FluxToFlux implements Function, Flux> { + @Override public Flux apply(Flux t) { return t.map(f -> new Bar()); } + } private static class FluxMessageToFluxMessage implements Function>, Flux>> { + @Override public Flux> apply(Flux> t) { return t.map(f -> MessageBuilder.withPayload(new Bar()) .copyHeadersIfAbsent(f.getHeaders()).build()); } + } private static class Foo { + } private static class Bar { + } + } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalogTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalogTests.java index 3e9104df6..19456737d 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalogTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/catalog/InMemoryFunctionCatalogTests.java @@ -1,11 +1,11 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -16,20 +16,20 @@ package org.springframework.cloud.function.context.catalog; +import java.util.function.Function; + +import org.junit.Test; + +import org.springframework.cloud.function.context.FunctionRegistration; +import org.springframework.cloud.function.context.FunctionType; +import org.springframework.cloud.function.core.FluxFunction; + import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; -import java.util.function.Function; - -import org.junit.Test; -import org.springframework.cloud.function.context.FunctionRegistration; -import org.springframework.cloud.function.context.FunctionType; -import org.springframework.cloud.function.core.FluxFunction; - /** - * * @author Oleg Zhurakousky * */ @@ -38,8 +38,8 @@ public class InMemoryFunctionCatalogTests { @Test public void testFunctionRegistration() { TestFunction function = new TestFunction(); - FunctionRegistration registration = new FunctionRegistration<>(function, "foo") - .type(FunctionType.of(TestFunction.class).getType()); + FunctionRegistration registration = new FunctionRegistration<>( + function, "foo").type(FunctionType.of(TestFunction.class).getType()); InMemoryFunctionCatalog catalog = new InMemoryFunctionCatalog(); catalog.register(registration); FunctionRegistration registration2 = catalog.getRegistration(function); @@ -49,8 +49,8 @@ public class InMemoryFunctionCatalogTests { @Test public void testFunctionLookup() { TestFunction function = new TestFunction(); - FunctionRegistration registration = new FunctionRegistration<>(function, "foo") - .type(FunctionType.of(TestFunction.class).getType()); + FunctionRegistration registration = new FunctionRegistration<>( + function, "foo").type(FunctionType.of(TestFunction.class).getType()); InMemoryFunctionCatalog catalog = new InMemoryFunctionCatalog(); catalog.register(registration); @@ -63,9 +63,12 @@ public class InMemoryFunctionCatalogTests { } private static class TestFunction implements Function { + @Override public String apply(Integer t) { return "i=" + t; } + } + } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java index cf7f4dc6c..e8572ee1a 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/BeanFactoryFunctionCatalogTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -26,6 +26,8 @@ import java.util.function.Function; import java.util.function.Supplier; import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.FunctionType; @@ -34,9 +36,6 @@ import org.springframework.cloud.function.context.config.ContextFunctionCatalogA import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @@ -48,56 +47,59 @@ public class BeanFactoryFunctionCatalogTests { @Test public void basicRegistrationFeatures() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - Function, Flux> foos = processor.lookup(Function.class, + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + Function, Flux> foos = this.processor.lookup(Function.class, "foos"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void lookupFunctionWithEmptyName() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - Function, Flux> foos = processor.lookup(Function.class, ""); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + Function, Flux> foos = this.processor.lookup(Function.class, + ""); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void lookupFunctionWithNoType() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - Function, Flux> foos = processor.lookup("foos"); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + Function, Flux> foos = this.processor.lookup("foos"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void registerFunctionWithType() { - processor.register(new FunctionRegistration>( + this.processor.register(new FunctionRegistration>( (Integer i) -> "i=" + i, "foos").type( FunctionType.from(Integer.class).to(String.class).getType())); - Function, Flux> foos = processor.lookup(Function.class, ""); + Function, Flux> foos = this.processor.lookup(Function.class, + ""); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("i=2"); } @Test public void registerFunctionWithFluxType() { - processor + this.processor .register(new FunctionRegistration, Flux>>( ints -> ints.map(i -> "i=" + i), "foos") .type(FunctionType.from(Integer.class).to(String.class) .wrap(Flux.class).getType())); - Function, Flux> foos = processor.lookup(Function.class, ""); + Function, Flux> foos = this.processor.lookup(Function.class, + ""); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("i=2"); } @Test public void registerFunctionWithMonoType() { - processor.register( + this.processor.register( new FunctionRegistration, Mono>>>( flux -> flux.collect(HashMap::new, - (map, word) -> map.merge(word, 1, Integer::sum)), "foos") - .type(FunctionType.from(String.class) - .to(Map.class) - .wrap(Flux.class, Mono.class).getType())); - Function, Mono>> foos = processor + (map, word) -> map.merge(word, 1, Integer::sum)), + "foos").type( + FunctionType.from(String.class).to(Map.class) + .wrap(Flux.class, Mono.class).getType())); + Function, Mono>> foos = this.processor .lookup(Function.class, ""); assertThat(foos.apply(Flux.just("one", "one", "two")).block()) .containsEntry("one", 2); @@ -105,16 +107,16 @@ public class BeanFactoryFunctionCatalogTests { @Test public void lookupNonExistentConsumerWithEmptyName() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - Consumer> foos = processor.lookup(Consumer.class, ""); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + Consumer> foos = this.processor.lookup(Consumer.class, ""); assertThat(foos).isNull(); } @Test public void composeFunction() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - processor.register(new FunctionRegistration<>(new Bars(), "bars")); - Function, Flux> foos = processor.lookup(Function.class, + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + this.processor.register(new FunctionRegistration<>(new Bars(), "bars")); + Function, Flux> foos = this.processor.lookup(Function.class, "foos,bars"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4"); } @@ -122,51 +124,60 @@ public class BeanFactoryFunctionCatalogTests { @Test public void composeWithFiniteFunction() { Function func1 = x -> x.toUpperCase(); - processor.register(new FunctionRegistration<>(func1, "func1")); - processor.register(new FunctionRegistration<>(new FluxThenMonoFunction(), "func2")); - Function, Mono> foos = processor.lookup(Function.class, "func1,func2"); - assertThat(foos.apply(Flux.fromArray(new String[] {"a", "b", "c"})).block()).isEqualTo(3); + this.processor.register(new FunctionRegistration<>(func1, "func1")); + this.processor.register( + new FunctionRegistration<>(new FluxThenMonoFunction(), "func2")); + Function, Mono> foos = this.processor.lookup(Function.class, + "func1,func2"); + assertThat(foos.apply(Flux.fromArray(new String[] { "a", "b", "c" })).block()) + .isEqualTo(3); } @Test public void composeWithFiniteFunctionAndContinueWithCompatible() { Function func1 = x -> x.toUpperCase(); - processor.register(new FunctionRegistration<>(func1, "func1")); - processor.register(new FunctionRegistration<>(new FluxThenMonoFunction(), "func2")); - processor.register(new FunctionRegistration<>(new MonoThenFluxFunction(), "func3")); - Function, Flux> foos = processor.lookup(Function.class, "func1,func2,func3"); - assertThat(foos.apply(Flux.fromArray(new String[] {"a", "b", "c"})).collectList().block().size()).isEqualTo(3); + this.processor.register(new FunctionRegistration<>(func1, "func1")); + this.processor.register( + new FunctionRegistration<>(new FluxThenMonoFunction(), "func2")); + this.processor.register( + new FunctionRegistration<>(new MonoThenFluxFunction(), "func3")); + Function, Flux> foos = this.processor.lookup(Function.class, + "func1,func2,func3"); + assertThat(foos.apply(Flux.fromArray(new String[] { "a", "b", "c" })) + .collectList().block().size()).isEqualTo(3); } - @Test(expected=IllegalStateException.class) + @Test(expected = IllegalStateException.class) public void composeIncompatibleFunctions() { Function func1 = x -> x.toUpperCase(); - processor.register(new FunctionRegistration<>(func1, "func1")); - processor.register(new FunctionRegistration<>(new FluxThenMonoFunction(), "func2")); - processor.lookup(Function.class, "func2,func1"); + this.processor.register(new FunctionRegistration<>(func1, "func1")); + this.processor.register( + new FunctionRegistration<>(new FluxThenMonoFunction(), "func2")); + this.processor.lookup(Function.class, "func2,func1"); } @Test public void composeSupplier() { - processor.register(new FunctionRegistration<>(new Source(), "numbers")); - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - Supplier> foos = processor.lookup(Supplier.class, "numbers,foos"); + this.processor.register(new FunctionRegistration<>(new Source(), "numbers")); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + Supplier> foos = this.processor.lookup(Supplier.class, + "numbers,foos"); assertThat(foos.get().blockFirst()).isEqualTo("6"); } @Test public void composeUniqueSupplier() { - processor.register(new FunctionRegistration<>(new Source(), "numbers")); - Supplier> foos = processor.lookup(Supplier.class, ""); + this.processor.register(new FunctionRegistration<>(new Source(), "numbers")); + Supplier> foos = this.processor.lookup(Supplier.class, ""); assertThat(foos.get().blockFirst()).isEqualTo(3); } @Test public void composeConsumer() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); Sink sink = new Sink(); - processor.register(new FunctionRegistration<>(sink, "sink")); - Function, Mono> foos = processor.lookup(Function.class, + this.processor.register(new FunctionRegistration<>(sink, "sink")); + Function, Mono> foos = this.processor.lookup(Function.class, "foos,sink"); foos.apply(Flux.just(2)).subscribe(); assertThat(sink.values).contains("4"); @@ -175,8 +186,9 @@ public class BeanFactoryFunctionCatalogTests { @Test public void composeUniqueConsumer() { Sink sink = new Sink(); - processor.register(new FunctionRegistration<>(sink, "sink")); - Function, Mono> foos = processor.lookup(Function.class, ""); + this.processor.register(new FunctionRegistration<>(sink, "sink")); + Function, Mono> foos = this.processor.lookup(Function.class, + ""); foos.apply(Flux.just("2")).subscribe(); assertThat(sink.values).contains("2"); } @@ -185,36 +197,36 @@ public class BeanFactoryFunctionCatalogTests { public void composeSupplierAndConsumer() { AtomicReference ref = new AtomicReference(); Supplier s = () -> "hello"; - processor.register(new FunctionRegistration<>(s, "supplier")); + this.processor.register(new FunctionRegistration<>(s, "supplier")); Consumer c = x -> ref.set(x.toUpperCase()); - processor.register(new FunctionRegistration<>(c, "consumer")); - Supplier> f = processor.lookup("supplier|consumer"); - ((Mono)f.get()).block(); + this.processor.register(new FunctionRegistration<>(c, "consumer")); + Supplier> f = this.processor.lookup("supplier|consumer"); + ((Mono) f.get()).block(); assertThat(ref.get()).isEqualTo("HELLO"); } - @Test(expected=IllegalStateException.class) + @Test(expected = IllegalStateException.class) public void failComposeSupplierWithMultipleConsumers() { AtomicReference ref = new AtomicReference(); Supplier s = () -> "hello"; - processor.register(new FunctionRegistration<>(s, "supplier")); + this.processor.register(new FunctionRegistration<>(s, "supplier")); Consumer c = x -> ref.set(x.toUpperCase()); - processor.register(new FunctionRegistration<>(c, "consumer")); + this.processor.register(new FunctionRegistration<>(c, "consumer")); Consumer z = x -> ref.set(x.toUpperCase()); - processor.register(new FunctionRegistration<>(z, "z")); - processor.lookup("supplier|consumer|z"); + this.processor.register(new FunctionRegistration<>(z, "z")); + this.processor.lookup("supplier|consumer|z"); } @Test public void composeSupplierAndMultipleFunctions() { Supplier s = () -> "hello"; - processor.register(new FunctionRegistration<>(s, "supplier")); + this.processor.register(new FunctionRegistration<>(s, "supplier")); Function uppercase = x -> x.toUpperCase(); - processor.register(new FunctionRegistration<>(uppercase, "uppercase")); + this.processor.register(new FunctionRegistration<>(uppercase, "uppercase")); Function concat = x -> x + x; - processor.register(new FunctionRegistration<>(concat, "concat")); + this.processor.register(new FunctionRegistration<>(concat, "concat")); - Supplier> f = processor.lookup("supplier|uppercase|concat"); + Supplier> f = this.processor.lookup("supplier|uppercase|concat"); assertThat(f.get().blockFirst()).isEqualTo("HELLOHELLO"); } @@ -234,7 +246,7 @@ public class BeanFactoryFunctionCatalogTests { @Override public void accept(String value) { - values.add(value); + this.values.add(value); } } @@ -257,20 +269,24 @@ public class BeanFactoryFunctionCatalogTests { } - protected static class FluxThenMonoFunction implements Function, Mono> { + protected static class FluxThenMonoFunction + implements Function, Mono> { @Override public Mono apply(Flux t) { return t.count(); } + } - protected static class MonoThenFluxFunction implements Function, Flux> { + protected static class MonoThenFluxFunction + implements Function, Flux> { @Override public Flux apply(Mono t) { return Flux.range(0, Integer.parseInt(t.block().toString())); } + } } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java index 70aa14a46..9a0ccdff1 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2012-2019-2018 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. @@ -30,6 +30,8 @@ import java.util.stream.Collectors; import org.junit.After; import org.junit.Test; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Qualifier; @@ -65,9 +67,6 @@ import org.springframework.util.StreamUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @author Artem Bilan @@ -75,15 +74,22 @@ import reactor.core.publisher.Mono; */ public class ContextFunctionCatalogAutoConfigurationTests { - private ConfigurableApplicationContext context; - private FunctionCatalog catalog; - private FunctionInspector inspector; private static String value; + private ConfigurableApplicationContext context; + + private FunctionCatalog catalog; + + private FunctionInspector inspector; + + public static void set(Object value) { + ContextFunctionCatalogAutoConfigurationTests.value = value.toString(); + } + @After public void close() { - if (context != null) { - context.close(); + if (this.context != null) { + this.context.close(); } ContextFunctionCatalogAutoConfigurationTests.value = null; } @@ -91,280 +97,325 @@ public class ContextFunctionCatalogAutoConfigurationTests { @Test public void lookUps() { create(SimpleConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(context.getBean("function2")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function,function2")) - .isInstanceOf(Function.class); - Function, Flux> f = catalog.lookup(Function.class, + assertThat(this.context.getBean("function2")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, + "function,function2")).isInstanceOf(Function.class); + Function, Flux> f = this.catalog.lookup(Function.class, "function,function2,function3"); assertThat(f).isInstanceOf(Function.class); assertThat(f.apply(Flux.just("hello")).blockFirst()) .isEqualTo("HELLOfunction2function3"); - assertThat(context.getBean("supplierFoo")).isInstanceOf(Supplier.class); - assertThat((Supplier) catalog.lookup(Supplier.class, "supplierFoo")) + assertThat(this.context.getBean("supplierFoo")).isInstanceOf(Supplier.class); + assertThat((Supplier) this.catalog.lookup(Supplier.class, "supplierFoo")) .isInstanceOf(Supplier.class); - assertThat(context.getBean("supplier_Foo")).isInstanceOf(Supplier.class); - assertThat((Supplier) catalog.lookup(Supplier.class, "supplier_Foo")) + assertThat(this.context.getBean("supplier_Foo")).isInstanceOf(Supplier.class); + assertThat((Supplier) this.catalog.lookup(Supplier.class, "supplier_Foo")) .isInstanceOf(Supplier.class); } @Test public void ambiguousFunction() { create(AmbiguousConfiguration.class); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat((Supplier) catalog.lookup(Supplier.class, "foos")) + assertThat((Supplier) this.catalog.lookup(Supplier.class, "foos")) .isInstanceOf(Supplier.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); - assertThat(inspector.getOutputType(catalog.lookup(Supplier.class, "foos"))) - .isEqualTo(Foo.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); + assertThat( + this.inspector.getOutputType(this.catalog.lookup(Supplier.class, "foos"))) + .isEqualTo(Foo.class); } @Test public void configurationFunction() { create(FunctionConfiguration.class); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); - assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(Foo.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos"))) - .isEqualTo(Flux.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); + assertThat( + this.inspector.getOutputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(Foo.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(Flux.class); } @Test public void dependencyInjection() { create(DependencyInjectionConfiguration.class); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); } @Test public void externalDependencyInjection() { create(ExternalDependencyConfiguration.class); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); } @Test public void composedFunction() { create(MultipleConfiguration.class); - assertThat((Function) catalog.lookup(Function.class, "foos,bars")) + assertThat((Function) this.catalog.lookup(Function.class, "foos,bars")) .isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "names,foos")) + assertThat((Function) this.catalog.lookup(Function.class, "names,foos")) .isNull(); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos,bars"))) - .isAssignableFrom(String.class); - assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos,bars"))) - .isAssignableFrom(Bar.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "foos,bars"))) + .isAssignableFrom(String.class); + assertThat(this.inspector + .getOutputType(this.catalog.lookup(Function.class, "foos,bars"))) + .isAssignableFrom(Bar.class); } @Test public void composedSupplier() { create(MultipleConfiguration.class); - assertThat((Supplier) catalog.lookup(Supplier.class, "names,foos")) + assertThat((Supplier) this.catalog.lookup(Supplier.class, "names,foos")) .isInstanceOf(Supplier.class); - assertThat((Function) catalog.lookup(Function.class, "names,foos")) + assertThat((Function) this.catalog.lookup(Function.class, "names,foos")) .isNull(); - assertThat(inspector.getOutputType(catalog.lookup(Supplier.class, "names,foos"))) - .isAssignableFrom(Foo.class); + assertThat(this.inspector + .getOutputType(this.catalog.lookup(Supplier.class, "names,foos"))) + .isAssignableFrom(Foo.class); // The input type is the same as the input type of the first element in the chain - assertThat(inspector.getInputType(catalog.lookup(Supplier.class, "names,foos"))) - .isAssignableFrom(Void.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Supplier.class, "names,foos"))) + .isAssignableFrom(Void.class); } @Test public void composedConsumer() { create(MultipleConfiguration.class); - assertThat((Consumer) catalog.lookup(Consumer.class, "foos,print")).isNull(); - assertThat((Function) catalog.lookup(Function.class, "foos,print")) + assertThat((Consumer) this.catalog.lookup(Consumer.class, "foos,print")) + .isNull(); + assertThat((Function) this.catalog.lookup(Function.class, "foos,print")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos,print"))) - .isAssignableFrom(String.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "foos,print"))) + .isAssignableFrom(String.class); // The output type is the same as the output type of the last element in the chain - assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos,print"))) - .isAssignableFrom(Void.class); + assertThat(this.inspector + .getOutputType(this.catalog.lookup(Function.class, "foos,print"))) + .isAssignableFrom(Void.class); } @Test public void genericFunction() { create(GenericConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); } @Test public void fluxMessageFunction() { create(FluxMessageConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.isMessage(catalog.lookup(Function.class, "function"))) - .isTrue(); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(String.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Flux.class); + assertThat( + this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) + .isTrue(); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Flux.class); } @Test public void publisherMessageFunction() { create(PublisherMessageConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.isMessage(catalog.lookup(Function.class, "function"))) - .isTrue(); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(String.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Publisher.class); + assertThat( + this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) + .isTrue(); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Publisher.class); } @Test public void monoFunction() { create(MonoConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.isMessage(catalog.lookup(Function.class, "function"))) - .isFalse(); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(String.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Flux.class); - assertThat(inspector.getOutputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Mono.class); + assertThat( + this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) + .isFalse(); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Flux.class); + assertThat(this.inspector + .getOutputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Mono.class); } @Test public void messageFunction() { create(MessageConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.isMessage(catalog.lookup(Function.class, "function"))) - .isTrue(); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(String.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(String.class); + assertThat( + this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) + .isTrue(); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(String.class); } @Test public void genericFluxFunction() { create(GenericFluxConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Flux.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Flux.class); } @Test public void externalFunction() { create(ExternalConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); } @Test public void singletonFunction() { create(SingletonConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Integer.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Integer.class); } @Test public void singletonMessageFunction() { create(SingletonMessageConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); - assertThat(inspector.isMessage(catalog.lookup(Function.class, "function"))) - .isTrue(); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Integer.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Integer.class); + assertThat( + this.inspector.isMessage(this.catalog.lookup(Function.class, "function"))) + .isTrue(); } @Test public void nonParametericTypeFunction() { create(NonParametricTypeSingletonConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Integer.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Integer.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Integer.class); } @Test public void componentScanBeanFunction() { create(ComponentScanBeanConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); } @Test public void componentScanFunction() { create(ComponentScanConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "function"))) - .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "function"))) + .isAssignableFrom(Map.class); } @Test public void componentScanJarFunction() { try { create("greeter.jar", ComponentScanJarConfiguration.class); - assertThat(context.getBean("greeter")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "greeter")) + assertThat(this.context.getBean("greeter")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "greeter")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "greeter"))) - .isAssignableFrom(String.class); - assertThat( - inspector.getInputWrapper(catalog.lookup(Function.class, "greeter"))) + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "greeter"))) + .isAssignableFrom(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "greeter"))) .isAssignableFrom(String.class); } finally { @@ -372,7 +423,6 @@ public class ContextFunctionCatalogAutoConfigurationTests { } } - private void create(String jarfile, Class config, String... props) { try { URL[] urls = new URL[] { new ClassPathResource(jarfile).getURL() }; @@ -388,64 +438,67 @@ public class ContextFunctionCatalogAutoConfigurationTests { @Test public void simpleFunction() { create(SimpleConfiguration.class); - Object bean = context.getBean("function"); + Object bean = this.context.getBean("function"); assertThat(bean).isInstanceOf(Function.class); - Function, Flux> function = catalog.lookup(Function.class, - "function"); + Function, Flux> function = this.catalog + .lookup(Function.class, "function"); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO"); assertThat(bean).isNotSameAs(function); - assertThat(inspector.getRegistration(bean)).isNotNull(); - assertThat(inspector.getRegistration(bean).getType()) - .isEqualTo(inspector.getRegistration(function).getType()); + assertThat(this.inspector.getRegistration(bean)).isNotNull(); + assertThat(this.inspector.getRegistration(bean).getType()) + .isEqualTo(this.inspector.getRegistration(function).getType()); } @Test public void simpleSupplier() { create(SimpleConfiguration.class); - assertThat(context.getBean("supplier")).isInstanceOf(Supplier.class); - Supplier> supplier = catalog.lookup(Supplier.class, "supplier"); + assertThat(this.context.getBean("supplier")).isInstanceOf(Supplier.class); + Supplier> supplier = this.catalog.lookup(Supplier.class, "supplier"); assertThat(supplier.get().blockFirst()).isEqualTo("hello"); } @Test public void simpleConsumer() { create(SimpleConfiguration.class); - assertThat(context.getBean("consumer")).isInstanceOf(Consumer.class); - Function, Mono> consumer = catalog.lookup(Function.class, + assertThat(this.context.getBean("consumer")).isInstanceOf(Consumer.class); + Function, Mono> consumer = this.catalog.lookup(Function.class, "consumer"); consumer.apply(Flux.just("foo", "bar")).subscribe(); - assertThat(context.getBean(SimpleConfiguration.class).list).hasSize(2); + assertThat(this.context.getBean(SimpleConfiguration.class).list).hasSize(2); } @Test public void qualifiedBean() { create(QualifiedConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")).isNull(); - assertThat((Function) catalog.lookup(Function.class, "other")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) + .isNull(); + assertThat((Function) this.catalog.lookup(Function.class, "other")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "other"))) - .isEqualTo(String.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "other"))) + .isEqualTo(String.class); } @Test public void aliasBean() { create(AliasConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isNotNull(); - assertThat((Function) catalog.lookup(Function.class, "other")) + assertThat((Function) this.catalog.lookup(Function.class, "other")) .isInstanceOf(Function.class); } @Test public void registrationBean() { create(RegistrationConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")).isNull(); - assertThat((Function) catalog.lookup(Function.class, "registration")) + assertThat(this.context.getBean("function")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isNull(); - assertThat((Function) catalog.lookup(Function.class, "other")) + assertThat((Function) this.catalog.lookup(Function.class, "registration")) + .isNull(); + assertThat((Function) this.catalog.lookup(Function.class, "other")) .isInstanceOf(Function.class); } @@ -455,11 +508,12 @@ public class ContextFunctionCatalogAutoConfigurationTests { "spring.cloud.function.compile.foos.lambda=v -> v.toUpperCase()", "spring.cloud.function.compile.foos.inputType=String", "spring.cloud.function.compile.foos.outputType=String"); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); } @Test @@ -471,11 +525,12 @@ public class ContextFunctionCatalogAutoConfigurationTests { StreamUtils.copy(compiled.getGeneratedClassBytes(), resource.getOutputStream()); create(EmptyConfiguration.class, "spring.cloud.function.imports.foos.location=file:./target/foos.fun"); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); } @Test @@ -485,12 +540,13 @@ public class ContextFunctionCatalogAutoConfigurationTests { + "::set", "spring.cloud.function.compile.foos.type=consumer", "spring.cloud.function.compile.foos.inputType=String"); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); @SuppressWarnings("unchecked") - Consumer consumer = (Consumer) context.getBean("foos"); + Consumer consumer = (Consumer) this.context.getBean("foos"); consumer.accept("hello"); assertThat(ContextFunctionCatalogAutoConfigurationTests.value).isEqualTo("hello"); } @@ -501,12 +557,13 @@ public class ContextFunctionCatalogAutoConfigurationTests { "spring.cloud.function.compile.foos.lambda=f -> f.subscribe(" + getClass().getName() + "::set)", "spring.cloud.function.compile.foos.type=consumer"); - assertThat((Consumer) catalog.lookup(Consumer.class, "foos")) + assertThat((Consumer) this.catalog.lookup(Consumer.class, "foos")) .isInstanceOf(Consumer.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Consumer.class, "foos"))) - .isEqualTo(Flux.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Consumer.class, "foos"))) + .isEqualTo(Flux.class); @SuppressWarnings("unchecked") - Consumer> consumer = (Consumer>) context + Consumer> consumer = (Consumer>) this.context .getBean("foos"); consumer.accept(Flux.just("hello")); assertThat(ContextFunctionCatalogAutoConfigurationTests.value).isEqualTo("hello"); @@ -516,7 +573,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { public void factoryBeanFunction() { create(FactoryBeanConfiguration.class); assertThat(this.context.getBean("function")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); Function, Flux> f = this.catalog.lookup(Function.class, "function"); @@ -528,23 +585,21 @@ public class ContextFunctionCatalogAutoConfigurationTests { } private void create(Class[] types, String... props) { - context = new SpringApplicationBuilder(types).properties(props).run(); - catalog = context.getBean(FunctionCatalog.class); - inspector = context.getBean(FunctionInspector.class); - } - - public static void set(Object value) { - ContextFunctionCatalogAutoConfigurationTests.value = value.toString(); + this.context = new SpringApplicationBuilder(types).properties(props).run(); + this.catalog = this.context.getBean(FunctionCatalog.class); + this.inspector = this.context.getBean(FunctionInspector.class); } @EnableAutoConfiguration @Configuration protected static class EmptyConfiguration { + } @EnableAutoConfiguration @Configuration protected static class SimpleConfiguration { + private List list = new ArrayList<>(); @Bean @@ -574,8 +629,9 @@ public class ContextFunctionCatalogAutoConfigurationTests { @Bean public Consumer consumer() { - return value -> list.add(value); + return value -> this.list.add(value); } + } @EnableAutoConfiguration @@ -591,6 +647,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { public String value() { return "Hello"; } + } @EnableAutoConfiguration @@ -607,6 +664,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { public String value() { return "Hello"; } + } @EnableAutoConfiguration @@ -618,6 +676,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { public String value() { return "Hello"; } + } @EnableAutoConfiguration @@ -634,11 +693,13 @@ public class ContextFunctionCatalogAutoConfigurationTests { public Supplier supplier() { return () -> new Foo("bar"); } + } @EnableAutoConfiguration @Configuration protected static class MultipleConfiguration { + @Bean public Function foos() { return value -> new Foo(value.toUpperCase()); @@ -658,22 +719,26 @@ public class ContextFunctionCatalogAutoConfigurationTests { public Supplier names() { return () -> "Mark"; } + } @EnableAutoConfiguration @Configuration protected static class GenericConfiguration { + @Bean public Function, Map> function() { return m -> m.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toString().toUpperCase())); } + } @EnableAutoConfiguration @Configuration @Import(GenericFunction.class) protected static class ExternalConfiguration { + } @EnableAutoConfiguration @@ -685,6 +750,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { throws BeansException { beanFactory.registerSingleton("function", new SingletonFunction()); } + } @EnableAutoConfiguration @@ -697,15 +763,18 @@ public class ContextFunctionCatalogAutoConfigurationTests { throws BeansException { beanFactory.registerSingleton("function", new SingletonMessageFunction()); } + } @EnableAutoConfiguration @Configuration protected static class NonParametricTypeSingletonConfiguration { + @Bean public SingletonFunction function() { return new SingletonFunction(); } + } protected static class SingletonFunction implements Function { @@ -731,90 +800,108 @@ public class ContextFunctionCatalogAutoConfigurationTests { @Configuration @ComponentScan(basePackageClasses = GenericFunction.class) protected static class ComponentScanBeanConfiguration { + } @EnableAutoConfiguration @Configuration @ComponentScan(basePackageClasses = ScannedFunction.class) protected static class ComponentScanConfiguration { + } @EnableAutoConfiguration @Configuration protected static class ComponentScanJarConfiguration { + } @EnableAutoConfiguration @Configuration protected static class GenericFluxConfiguration { + @Bean public Function>, Flux>> function() { return flux -> flux.map(m -> m.entrySet().stream().collect(Collectors .toMap(e -> e.getKey(), e -> e.getValue().toString().toUpperCase()))); } + } @EnableAutoConfiguration @Configuration protected static class FluxMessageConfiguration { + @Bean public Function>, Flux>> function() { return flux -> flux.map(m -> MessageBuilder .withPayload(m.getPayload().toUpperCase()).build()); } + } @EnableAutoConfiguration @Configuration protected static class PublisherMessageConfiguration { + @Bean public Function>, Publisher>> function() { return flux -> Flux.from(flux).map(m -> MessageBuilder .withPayload(m.getPayload().toUpperCase()).build()); } + } @EnableAutoConfiguration @Configuration protected static class MonoConfiguration { + @Bean public Function, Mono>> function() { return flux -> flux.collect(HashMap::new, (map, word) -> map.merge(word, 1, Integer::sum)); } + } @EnableAutoConfiguration @Configuration protected static class MessageConfiguration { + @Bean public Function, Message> function() { return m -> MessageBuilder.withPayload(m.getPayload().toUpperCase()).build(); } + } @EnableAutoConfiguration @Configuration protected static class QualifiedConfiguration { + @Bean @Qualifier("other") public Function function() { return value -> value.toUpperCase(); } + } @EnableAutoConfiguration @Configuration protected static class AliasConfiguration { + @Bean({ "function", "other" }) public Function function() { return value -> value.toUpperCase(); } + } @EnableAutoConfiguration @Configuration protected static class RegistrationConfiguration { + @Bean public FunctionRegistration> registration() { return new FunctionRegistration>(function(), @@ -825,6 +912,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { public Function function() { return value -> value.toUpperCase(); } + } @EnableAutoConfiguration @@ -865,6 +953,7 @@ public class ContextFunctionCatalogAutoConfigurationTests { } public static class Foo { + private String value; public Foo(String value) { @@ -875,15 +964,17 @@ public class ContextFunctionCatalogAutoConfigurationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } public static class Bar { + private String message; public Bar(String value) { @@ -902,4 +993,5 @@ public class ContextFunctionCatalogAutoConfigurationTests { } } + } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java index 9abdea6b2..11f312a47 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionCatalogInitializerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2012-2019-2018 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. @@ -26,10 +26,11 @@ import java.util.function.Function; import java.util.function.Supplier; import com.google.gson.Gson; - import org.junit.After; import org.junit.Ignore; import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanCreationException; @@ -47,9 +48,6 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @@ -57,30 +55,34 @@ import reactor.core.publisher.Mono; public class ContextFunctionCatalogInitializerTests { private GenericApplicationContext context; + private FunctionCatalog catalog; + private FunctionInspector inspector; @After public void close() { - if (context != null) { - context.close(); + if (this.context != null) { + this.context.close(); } } @Test public void lookUps() { create(SimpleConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")) + .isInstanceOf(FunctionRegistration.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); } @Test public void properties() { create(PropertiesConfiguration.class, "app.greeting=hello"); - assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); + assertThat(this.context.getBean("function")) + .isInstanceOf(FunctionRegistration.class); @SuppressWarnings("unchecked") - Function, Flux> function = (Function, Flux>) catalog + Function, Flux> function = (Function, Flux>) this.catalog .lookup(Function.class, "function"); assertThat(function).isInstanceOf(Function.class); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("hello foo"); @@ -89,9 +91,10 @@ public class ContextFunctionCatalogInitializerTests { @Test public void value() { create(ValueConfiguration.class, "app.greeting=hello"); - assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); + assertThat(this.context.getBean("function")) + .isInstanceOf(FunctionRegistration.class); @SuppressWarnings("unchecked") - Function, Flux> function = (Function, Flux>) catalog + Function, Flux> function = (Function, Flux>) this.catalog .lookup(Function.class, "function"); assertThat(function).isInstanceOf(Function.class); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("hello foo"); @@ -101,9 +104,10 @@ public class ContextFunctionCatalogInitializerTests { @Ignore public void compose() { create(SimpleConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); + assertThat(this.context.getBean("function")) + .isInstanceOf(FunctionRegistration.class); @SuppressWarnings("unchecked") - Supplier> supplier = (Supplier>) catalog + Supplier> supplier = (Supplier>) this.catalog .lookup(Supplier.class, "supplier|function"); assertThat(supplier).isInstanceOf(Supplier.class); assertThat(supplier.get().blockFirst()).isEqualTo("HELLO"); @@ -113,8 +117,9 @@ public class ContextFunctionCatalogInitializerTests { @Test(expected = BeanCreationException.class) public void missingType() { create(MissingTypeConfiguration.class); - assertThat(context.getBean("function")).isInstanceOf(FunctionRegistration.class); - assertThat((Function) catalog.lookup(Function.class, "function")) + assertThat(this.context.getBean("function")) + .isInstanceOf(FunctionRegistration.class); + assertThat((Function) this.catalog.lookup(Function.class, "function")) .isInstanceOf(Function.class); // TODO: support for type inference from functional bean registrations } @@ -122,64 +127,70 @@ public class ContextFunctionCatalogInitializerTests { @Test public void configurationFunction() { create(FunctionConfiguration.class); - assertThat(context.getBean("foos")).isInstanceOf(Function.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(Function.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); - assertThat(inspector.getOutputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(Foo.class); - assertThat(inspector.getInputWrapper(catalog.lookup(Function.class, "foos"))) - .isEqualTo(Flux.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); + assertThat( + this.inspector.getOutputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(Foo.class); + assertThat(this.inspector + .getInputWrapper(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(Flux.class); } @Test public void dependencyInjection() { create(DependencyInjectionConfiguration.class); - assertThat(context.getBean("foos")).isInstanceOf(FunctionRegistration.class); - assertThat((Function) catalog.lookup(Function.class, "foos")) + assertThat(this.context.getBean("foos")).isInstanceOf(FunctionRegistration.class); + assertThat((Function) this.catalog.lookup(Function.class, "foos")) .isInstanceOf(Function.class); - assertThat(inspector.getInputType(catalog.lookup(Function.class, "foos"))) - .isEqualTo(String.class); + assertThat( + this.inspector.getInputType(this.catalog.lookup(Function.class, "foos"))) + .isEqualTo(String.class); } @Test public void simpleFunction() { create(SimpleConfiguration.class); - Object bean = context.getBean("function"); + Object bean = this.context.getBean("function"); assertThat(bean).isInstanceOf(FunctionRegistration.class); - Function, Flux> function = catalog.lookup(Function.class, - "function"); + Function, Flux> function = this.catalog + .lookup(Function.class, "function"); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO"); assertThat(bean).isNotSameAs(function); - assertThat(inspector.getRegistration(function)).isNotNull(); - assertThat(inspector.getRegistration(function).getType()).isEqualTo( + assertThat(this.inspector.getRegistration(function)).isNotNull(); + assertThat(this.inspector.getRegistration(function).getType()).isEqualTo( FunctionType.from(String.class).to(String.class).wrap(Flux.class)); } @Test public void simpleSupplier() { create(SimpleConfiguration.class); - assertThat(context.getBean("supplier")).isInstanceOf(FunctionRegistration.class); - Supplier> supplier = catalog.lookup(Supplier.class, "supplier"); + assertThat(this.context.getBean("supplier")) + .isInstanceOf(FunctionRegistration.class); + Supplier> supplier = this.catalog.lookup(Supplier.class, "supplier"); assertThat(supplier.get().blockFirst()).isEqualTo("hello"); } @Test public void simpleConsumer() { create(SimpleConfiguration.class); - assertThat(context.getBean("consumer")).isInstanceOf(FunctionRegistration.class); - Function, Mono> consumer = catalog.lookup(Function.class, + assertThat(this.context.getBean("consumer")) + .isInstanceOf(FunctionRegistration.class); + Function, Mono> consumer = this.catalog.lookup(Function.class, "consumer"); consumer.apply(Flux.just("foo", "bar")).subscribe(); - assertThat(context.getBean(SimpleConfiguration.class).list).hasSize(2); + assertThat(this.context.getBean(SimpleConfiguration.class).list).hasSize(2); } @Test public void overrideGson() { create(GsonConfiguration.class); - Gson user = context.getBean(GsonConfiguration.class).gson(); - Gson bean = context.getBean(Gson.class); + Gson user = this.context.getBean(GsonConfiguration.class).gson(); + Gson bean = this.context.getBean(Gson.class); assertThat(user).isSameAs(bean); } @@ -193,7 +204,7 @@ public class ContextFunctionCatalogInitializerTests { private void create(ApplicationContextInitializer[] types, String... props) { - context = new GenericApplicationContext(); + this.context = new GenericApplicationContext(); Map map = new HashMap<>(); for (String prop : props) { String[] array = StringUtils.delimitedListToStringArray(prop, "="); @@ -202,17 +213,17 @@ public class ContextFunctionCatalogInitializerTests { map.put(key, value); } if (!map.isEmpty()) { - context.getEnvironment().getPropertySources() + this.context.getEnvironment().getPropertySources() .addFirst(new MapPropertySource("testProperties", map)); } for (ApplicationContextInitializer type : types) { - type.initialize(context); + type.initialize(this.context); } - new ContextFunctionCatalogInitializer.ContextFunctionCatalogBeanRegistrar(context) - .postProcessBeanDefinitionRegistry(context); - context.refresh(); - catalog = context.getBean(FunctionCatalog.class); - inspector = context.getBean(FunctionInspector.class); + new ContextFunctionCatalogInitializer.ContextFunctionCatalogBeanRegistrar( + this.context).postProcessBeanDefinitionRegistry(this.context); + this.context.refresh(); + this.catalog = this.context.getBean(FunctionCatalog.class); + this.inspector = this.context.getBean(FunctionInspector.class); } protected static class EmptyConfiguration @@ -221,6 +232,7 @@ public class ContextFunctionCatalogInitializerTests { @Override public void initialize(GenericApplicationContext applicationContext) { } + } protected static class MissingTypeConfiguration @@ -270,8 +282,9 @@ public class ContextFunctionCatalogInitializerTests { @Bean public Consumer consumer() { - return value -> list.add(value); + return value -> this.list.add(value); } + } @ConfigurationProperties("app") @@ -298,7 +311,7 @@ public class ContextFunctionCatalogInitializerTests { @Bean public Function function() { - return value -> greeting + " " + value; + return value -> this.greeting + " " + value; } } @@ -319,7 +332,7 @@ public class ContextFunctionCatalogInitializerTests { @Bean public Function function() { - return value -> greeting + " " + value; + return value -> this.greeting + " " + value; } } @@ -363,6 +376,7 @@ public class ContextFunctionCatalogInitializerTests { public String value() { return "Hello"; } + } protected static class FunctionConfiguration @@ -386,9 +400,11 @@ public class ContextFunctionCatalogInitializerTests { public String value() { return "Hello"; } + } public static class Foo { + private String value; public Foo(String value) { @@ -399,12 +415,13 @@ public class ContextFunctionCatalogInitializerTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java index ee4a68c8b..27c27b14b 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/config/ContextFunctionPostProcessorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -16,9 +16,6 @@ package org.springframework.cloud.function.context.config; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assert.assertNull; - import java.io.File; import java.net.MalformedURLException; import java.net.URL; @@ -33,14 +30,17 @@ import java.util.function.Supplier; import org.junit.After; import org.junit.Test; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + import org.springframework.beans.BeanUtils; import org.springframework.cloud.function.context.FunctionRegistration; import org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration.ContextFunctionRegistry; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.util.ClassUtils; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertNull; /** * @author Dave Syer @@ -51,7 +51,9 @@ import reactor.core.publisher.Mono; public class ContextFunctionPostProcessorTests { private ContextFunctionRegistry processor = new ContextFunctionRegistry(); + private URLClassLoader classLoader; + private ClassLoader contextClassLoader; @After @@ -60,128 +62,136 @@ public class ContextFunctionPostProcessorTests { this.classLoader.close(); } if (Thread.currentThread().getContextClassLoader() != null) { - ClassUtils.overrideThreadContextClassLoader(contextClassLoader); + ClassUtils.overrideThreadContextClassLoader(this.contextClassLoader); } } @Test public void basicRegistrationFeatures() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); @SuppressWarnings("unchecked") - Function, Flux> foos = (Function, Flux>) processor + Function, Flux> foos = (Function, Flux>) this.processor .lookupFunction("foos"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void registrationThroughMerge() { - FunctionRegistration registration = new FunctionRegistration<>(new Foos(), "foos"); - processor.merge(Collections.singletonMap("foos", registration), + FunctionRegistration registration = new FunctionRegistration<>(new Foos(), + "foos"); + this.processor.merge(Collections.singletonMap("foos", registration), Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap()); @SuppressWarnings("unchecked") - Function, Flux> foos = (Function, Flux>) processor + Function, Flux> foos = (Function, Flux>) this.processor .lookupFunction("foos"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void registrationThroughMergeFromNamedFunction() { - processor.merge(Collections.emptyMap(), Collections.emptyMap(), + this.processor.merge(Collections.emptyMap(), Collections.emptyMap(), Collections.emptyMap(), Collections.singletonMap("foos", new Foos())); @SuppressWarnings("unchecked") - Function, Flux> foos = (Function, Flux>) processor + Function, Flux> foos = (Function, Flux>) this.processor .lookupFunction("foos"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void composeWithComma() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - processor.register(new FunctionRegistration<>(new Bars(), "bars")); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + this.processor.register(new FunctionRegistration<>(new Bars(), "bars")); @SuppressWarnings("unchecked") - Function, Flux> foos = (Function, Flux>) processor + Function, Flux> foos = (Function, Flux>) this.processor .lookupFunction("foos,bars"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4"); - assertThat(processor.getRegistration(foos).getNames()) + assertThat(this.processor.getRegistration(foos).getNames()) .containsExactly("foos|bars"); } @Test public void supplierAndFunction() { - processor.register(new FunctionRegistration>(() -> "foo", "supplier")); - processor.register(new FunctionRegistration>((x) -> x.toUpperCase(), "function")); + this.processor.register( + new FunctionRegistration>(() -> "foo", "supplier")); + this.processor.register(new FunctionRegistration>( + (x) -> x.toUpperCase(), "function")); @SuppressWarnings("unchecked") - Supplier> supplier = (Supplier>) processor.lookupSupplier("supplier|function"); + Supplier> supplier = (Supplier>) this.processor + .lookupSupplier("supplier|function"); assertThat(supplier.get().blockFirst()).isEqualTo("FOO"); - assertThat(processor.getRegistration(supplier).getNames()).containsExactly("supplier|function"); + assertThat(this.processor.getRegistration(supplier).getNames()) + .containsExactly("supplier|function"); } @SuppressWarnings("unchecked") @Test public void supplierAndConsumer() { - processor.register(new FunctionRegistration>(() -> "foo", "supplier")); - processor.register(new FunctionRegistration>(System.out::println, "consumer")); - Supplier> supplier = (Supplier>) processor.lookupSupplier("supplier|consumer"); + this.processor.register( + new FunctionRegistration>(() -> "foo", "supplier")); + this.processor.register(new FunctionRegistration>( + System.out::println, "consumer")); + Supplier> supplier = (Supplier>) this.processor + .lookupSupplier("supplier|consumer"); assertNull(supplier.get().block()); } @Test public void compose() { - processor.register(new FunctionRegistration<>(new Foos(), "foos")); - processor.register(new FunctionRegistration<>(new Bars(), "bars")); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); + this.processor.register(new FunctionRegistration<>(new Bars(), "bars")); @SuppressWarnings("unchecked") - Function, Flux> foos = (Function, Flux>) processor + Function, Flux> foos = (Function, Flux>) this.processor .lookupFunction("foos|bars"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("Hello 4"); - assertThat(processor.getRegistration(foos).getNames()) + assertThat(this.processor.getRegistration(foos).getNames()) .containsExactly("foos|bars"); } @Test public void composeWrapper() { - processor.register(new FunctionRegistration<>(new WrappedSource(), "ints")); - processor.register(new FunctionRegistration<>(new Foos(), "foos")); + this.processor.register(new FunctionRegistration<>(new WrappedSource(), "ints")); + this.processor.register(new FunctionRegistration<>(new Foos(), "foos")); @SuppressWarnings("unchecked") - Supplier> foos = (Supplier>) processor + Supplier> foos = (Supplier>) this.processor .lookupSupplier("ints|foos"); assertThat(foos.get().blockFirst()).isEqualTo("8"); - assertThat(processor.getRegistration(foos).getNames()) + assertThat(this.processor.getRegistration(foos).getNames()) .containsExactly("ints|foos"); - assertThat(processor.getRegistration(foos).getType().getOutputWrapper()) + assertThat(this.processor.getRegistration(foos).getType().getOutputWrapper()) .isEqualTo(Flux.class); } @Test public void isolatedFunction() { - contextClassLoader = ClassUtils + this.contextClassLoader = ClassUtils .overrideThreadContextClassLoader(getClass().getClassLoader()); - processor.register(new FunctionRegistration<>(create(Foos.class), "foos")); + this.processor.register(new FunctionRegistration<>(create(Foos.class), "foos")); @SuppressWarnings("unchecked") - Function, Flux> foos = (Function, Flux>) processor + Function, Flux> foos = (Function, Flux>) this.processor .lookupFunction("foos"); assertThat(foos.apply(Flux.just(2)).blockFirst()).isEqualTo("4"); } @Test public void isolatedSupplier() { - contextClassLoader = ClassUtils + this.contextClassLoader = ClassUtils .overrideThreadContextClassLoader(getClass().getClassLoader()); - processor.register( - new FunctionRegistration<>(create(Source.class), "source")); + this.processor + .register(new FunctionRegistration<>(create(Source.class), "source")); @SuppressWarnings("unchecked") - Supplier> source = (Supplier>) processor + Supplier> source = (Supplier>) this.processor .lookupSupplier("source"); assertThat(source.get().blockFirst()).isEqualTo(4); } @Test public void isolatedConsumer() { - contextClassLoader = ClassUtils + this.contextClassLoader = ClassUtils .overrideThreadContextClassLoader(getClass().getClassLoader()); Object target = create(Sink.class); - processor.register(new FunctionRegistration<>(target, "sink")); + this.processor.register(new FunctionRegistration<>(target, "sink")); @SuppressWarnings("unchecked") - Function, Mono> sink = (Function, Mono>) processor + Function, Mono> sink = (Function, Mono>) this.processor .lookupFunction("sink"); sink.apply(Flux.just("Hello")).subscribe(); @SuppressWarnings("unchecked") @@ -199,14 +209,14 @@ public class ContextFunctionPostProcessorTests { String pathEntry = jcpEntries.nextToken(); try { urls.add(new File(pathEntry).toURI().toURL()); - } catch (MalformedURLException e) { + } + catch (MalformedURLException e) { } } - this.classLoader = new URLClassLoader( - urls.toArray(new URL[0]), + this.classLoader = new URLClassLoader(urls.toArray(new URL[0]), getClass().getClassLoader().getParent()); - return BeanUtils - .instantiateClass(ClassUtils.resolveClassName(type.getName(), classLoader)); + return BeanUtils.instantiateClass( + ClassUtils.resolveClassName(type.getName(), this.classLoader)); } public static class Foos implements Function { @@ -239,7 +249,7 @@ public class ContextFunctionPostProcessorTests { public void accept(String t) { assertThat(ClassUtils.resolveClassName(Bar.class.getName(), null) .getClassLoader()).isEqualTo(getClass().getClassLoader()); - values.add(t); + this.values.add(t); } } @@ -263,6 +273,7 @@ public class ContextFunctionPostProcessorTests { } public static class Foo { + private String value; public Foo(String value) { @@ -273,15 +284,17 @@ public class ContextFunctionPostProcessorTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } public static class Bar { + private String message; public Bar(String value) { diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/string/FunctionalStringSourceTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/string/FunctionalStringSourceTests.java index d606b8de3..f8777550d 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/string/FunctionalStringSourceTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/string/FunctionalStringSourceTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cloud.function.context.FunctionCatalog; @@ -28,11 +29,9 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * Test that spring.main.sources works with the functional approach. - * + * * @author Dave Syer * */ @@ -45,15 +44,18 @@ public class FunctionalStringSourceTests { @Test public void words() throws Exception { - Function, Flux> function = catalog.lookup(Function.class, - "function"); + Function, Flux> function = this.catalog + .lookup(Function.class, "function"); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO"); } protected static class TestConfiguration implements Function { + @Override public String apply(String value) { return value.toUpperCase(); } + } + } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/test/FunctionalTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/test/FunctionalTests.java index 3d7818ff1..5c5c30c7f 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/test/FunctionalTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/context/test/FunctionalTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -28,8 +29,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -43,16 +42,19 @@ public class FunctionalTests { @Test public void words() throws Exception { - Function, Flux> function = catalog.lookup(Function.class, - "function"); + Function, Flux> function = this.catalog + .lookup(Function.class, "function"); assertThat(function.apply(Flux.just("foo")).blockFirst()).isEqualTo("FOO"); } @SpringBootConfiguration protected static class TestConfiguration implements Function { + @Override public String apply(String value) { return value.toUpperCase(); } + } + } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/inject/FooConfiguration.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/inject/FooConfiguration.java index 12d14c7ea..4148022ce 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/inject/FooConfiguration.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/inject/FooConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,8 +23,10 @@ import org.springframework.context.annotation.Configuration; @Configuration public class FooConfiguration { + @Bean public Function foos(String foo) { return value -> new Foo(foo + ": " + value.toUpperCase()); } -} \ No newline at end of file + +} diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/scan/ScannedFunction.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/scan/ScannedFunction.java index ffc70a99f..f7e6ad8ff 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/scan/ScannedFunction.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/scan/ScannedFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -29,9 +29,11 @@ import org.springframework.stereotype.Component; @Component("function") public class ScannedFunction implements Function, Map> { + @Override public Map apply(Map m) { return m.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toString().toUpperCase())); } + } diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/test/GenericFunction.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/test/GenericFunction.java index d0c5dcc3e..65f837128 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/test/GenericFunction.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/test/GenericFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -29,10 +29,11 @@ import org.springframework.context.annotation.Configuration; */ @Configuration public class GenericFunction { + @Bean public Function, Map> function() { return m -> m.entrySet().stream().collect(Collectors.toMap(e -> e.getKey(), e -> e.getValue().toString().toUpperCase())); } -} +} diff --git a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/util/JsonMapperTests.java b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/util/JsonMapperTests.java index bfd83bbdb..3688599ac 100644 --- a/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/util/JsonMapperTests.java +++ b/spring-cloud-function-context/src/test/java/org/springframework/cloud/function/util/JsonMapperTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -20,7 +20,6 @@ import java.util.List; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; - import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -43,29 +42,29 @@ public class JsonMapperTests { private JsonMapper mapper; + public JsonMapperTests(JsonMapper mapper) { + this.mapper = mapper; + } + @Parameters public static List params() { return Arrays.asList(new Object[] { new GsonMapper(new Gson()) }, new Object[] { new JacksonMapper(new ObjectMapper()) }); } - public JsonMapperTests(JsonMapper mapper) { - this.mapper = mapper; - } - @Test public void vanillaArray() { String json = "[{\"value\":\"foo\"},{\"value\":\"foo\"}]"; - List list = mapper.toObject(json, + List list = this.mapper.toObject(json, ResolvableType.forClassWithGenerics(List.class, Foo.class).getType()); assertThat(list).hasSize(2); assertThat(list.get(0).getValue()).isEqualTo("foo"); - assertThat(mapper.toString(list)).isEqualTo(json); + assertThat(this.mapper.toString(list)).isEqualTo(json); } @Test public void intArray() { - List list = mapper.toObject("[123,456]", + List list = this.mapper.toObject("[123,456]", ResolvableType.forClassWithGenerics(List.class, Integer.class).getType()); assertThat(list).hasSize(2); assertThat(list.get(0)).isEqualTo(123); @@ -73,7 +72,7 @@ public class JsonMapperTests { @Test public void emptyArray() { - List list = mapper.toObject("[]", + List list = this.mapper.toObject("[]", ResolvableType.forClassWithGenerics(List.class, Foo.class).getType()); assertThat(list).hasSize(0); } @@ -81,28 +80,29 @@ public class JsonMapperTests { @Test public void vanillaObject() { String json = "{\"value\":\"foo\"}"; - Foo foo = mapper.toObject(json, Foo.class); + Foo foo = this.mapper.toObject(json, Foo.class); assertThat(foo.getValue()).isEqualTo("foo"); - assertThat(mapper.toString(foo)).isEqualTo(json); + assertThat(this.mapper.toString(foo)).isEqualTo(json); } @Test public void intValue() { - int foo = mapper.toObject("123", Integer.class); + int foo = this.mapper.toObject("123", Integer.class); assertThat(foo).isEqualTo(123); } @Test public void empty() { - Foo foo = mapper.toObject("{}", Foo.class); + Foo foo = this.mapper.toObject("{}", Foo.class); assertThat(foo.getValue()).isNull(); } public static class Foo { + private String value; public String getValue() { - return value; + return this.value; } public void setValue(String value) { @@ -110,4 +110,5 @@ public class JsonMapperTests { } } + } diff --git a/spring-cloud-function-core/pom.xml b/spring-cloud-function-core/pom.xml index 397c3c66b..9c8134a16 100644 --- a/spring-cloud-function-core/pom.xml +++ b/spring-cloud-function-core/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 spring-cloud-function-core diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxConsumer.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxConsumer.java index 3add72f47..a21505c00 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxConsumer.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -26,9 +26,8 @@ import reactor.core.publisher.Mono; * Wrapper for a {@link Consumer} implementation that converts a non-reactive consumer * into a reactive function. * - * @author Dave Syer - * * @param input type of target consumer + * @author Dave Syer */ public class FluxConsumer implements Function, Mono>, FluxWrapper> { @@ -46,6 +45,7 @@ public class FluxConsumer @Override public Mono apply(Flux input) { - return input.doOnNext(consumer).then(); + return input.doOnNext(this.consumer).then(); } + } diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxFunction.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxFunction.java index 74bba239b..a45e8138d 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxFunction.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -24,19 +24,19 @@ import reactor.core.publisher.Flux; * {@link Function} implementation that wraps a target Function so that the target's * simple input and output types will be wrapped as {@link Flux} instances. * - * @author Mark Fisher - * * @param input type of target function * @param output type of target function + * @author Mark Fisher */ -public class FluxFunction implements Function, Flux>, FluxWrapper> { +public class FluxFunction + implements Function, Flux>, FluxWrapper> { private final Function function; public FluxFunction(Function function) { this.function = function; } - + @Override public Function getTarget() { return this.function; @@ -46,4 +46,5 @@ public class FluxFunction implements Function, Flux>, FluxWrapp public Flux apply(Flux input) { return input.map(i -> this.function.apply(i)); } + } diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxSupplier.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxSupplier.java index f736d0143..188e68cd9 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxSupplier.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,17 +23,16 @@ import java.util.stream.Stream; import reactor.core.publisher.Flux; /** - * {@link Supplier} implementation that wraps a target Supplier so that the - * target's simple output type will be wrapped in a {@link Flux} instance. - * If a {@link Duration} is provided, the Flux will produce output - * periodically, invoking the target Supplier's {@code get} method at each - * interval. If no Duration is provided, the target will be invoked only once. - * - * @author Mark Fisher + * {@link Supplier} implementation that wraps a target Supplier so that the target's + * simple output type will be wrapped in a {@link Flux} instance. If a {@link Duration} is + * provided, the Flux will produce output periodically, invoking the target Supplier's + * {@code get} method at each interval. If no Duration is provided, the target will be + * invoked only once. * * @param output type of target supplier + * @author Mark Fisher */ -public class FluxSupplier implements Supplier>, FluxWrapper> { +public class FluxSupplier implements Supplier>, FluxWrapper> { private final Supplier supplier; @@ -42,7 +41,7 @@ public class FluxSupplier implements Supplier>, FluxWrapper supplier) { this(supplier, null); } - + public FluxSupplier(Supplier supplier, Duration period) { this.supplier = supplier; this.period = period; @@ -52,12 +51,12 @@ public class FluxSupplier implements Supplier>, FluxWrapper getTarget() { return this.supplier; } - + @Override @SuppressWarnings({ "unchecked", "rawtypes" }) public Flux get() { if (this.period != null) { - return Flux.interval(this.period).map(i->this.supplier.get()); + return Flux.interval(this.period).map(i -> this.supplier.get()); } Object result = this.supplier.get(); if (result instanceof Stream) { @@ -65,4 +64,5 @@ public class FluxSupplier implements Supplier>, FluxWrapper type of {@link Flux} input of the target function + * @param type of {@link Mono} output of the target function * @author Oleg Zhurakousky * @since 2.0 - * - * @param type of {@link Flux} input of the target function - * @param type of {@link Mono} output of the target function */ -public class FluxToMonoFunction implements Function, Mono>, FluxWrapper, Mono>> { +public class FluxToMonoFunction + implements Function, Mono>, FluxWrapper, Mono>> { private final Function, Mono> function; @@ -43,11 +43,12 @@ public class FluxToMonoFunction implements Function, Mono>, Flux @Override public Function, Mono> getTarget() { - return function; + return this.function; } @Override public Mono apply(Flux input) { - return function.apply(input); + return this.function.apply(input); } + } diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxWrapper.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxWrapper.java index 9062b56bc..c6417bde4 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxWrapper.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FluxWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -17,11 +17,11 @@ package org.springframework.cloud.function.core; /** + * @param target type * @author Dave Syer - * */ public interface FluxWrapper { - + T getTarget(); } diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FunctionFactoryMetadata.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FunctionFactoryMetadata.java index 08b04c4af..b5220d736 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FunctionFactoryMetadata.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/FunctionFactoryMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,9 +19,8 @@ package org.springframework.cloud.function.core; import java.lang.reflect.Method; /** + * @param target type * @author Dave Syer - * - * @param */ public interface FunctionFactoryMetadata { @@ -29,4 +28,4 @@ public interface FunctionFactoryMetadata { F getTarget(); -} \ No newline at end of file +} diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/Isolated.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/Isolated.java index be93e1a04..9f3a65997 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/Isolated.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/Isolated.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,4 +23,5 @@ package org.springframework.cloud.function.core; public interface Isolated { ClassLoader getClassLoader(); + } diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedConsumer.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedConsumer.java index 91cb76aea..b7b8c7b9e 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedConsumer.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedConsumer.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -21,12 +21,13 @@ import java.util.function.Consumer; import org.springframework.util.ClassUtils; /** + * @param type to consume * @author Dave Syer - * */ public class IsolatedConsumer implements Consumer, Isolated { private final Consumer consumer; + private final ClassLoader classLoader; public IsolatedConsumer(Consumer consumer) { @@ -44,7 +45,7 @@ public class IsolatedConsumer implements Consumer, Isolated { ClassLoader context = ClassUtils .overrideThreadContextClassLoader(this.classLoader); try { - consumer.accept(item); + this.consumer.accept(item); } finally { ClassUtils.overrideThreadContextClassLoader(context); diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedFunction.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedFunction.java index d257d1af3..c5470f691 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedFunction.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -21,12 +21,14 @@ import java.util.function.Function; import org.springframework.util.ClassUtils; /** + * @param input type + * @param output type * @author Dave Syer - * */ public class IsolatedFunction implements Function, Isolated { private final Function function; + private final ClassLoader classLoader; public IsolatedFunction(Function function) { diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedSupplier.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedSupplier.java index 57cacab58..0868ff4fd 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedSupplier.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/IsolatedSupplier.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -21,12 +21,13 @@ import java.util.function.Supplier; import org.springframework.util.ClassUtils; /** + * @param supplied type * @author Dave Syer - * */ public class IsolatedSupplier implements Supplier, Isolated { private final Supplier supplier; + private final ClassLoader classLoader; public IsolatedSupplier(Supplier supplier) { @@ -44,7 +45,7 @@ public class IsolatedSupplier implements Supplier, Isolated { ClassLoader context = ClassUtils .overrideThreadContextClassLoader(this.classLoader); try { - return supplier.get(); + return this.supplier.get(); } finally { ClassUtils.overrideThreadContextClassLoader(context); diff --git a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/MonoToFluxFunction.java b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/MonoToFluxFunction.java index ad62e7dd6..1710873d7 100644 --- a/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/MonoToFluxFunction.java +++ b/spring-cloud-function-core/src/main/java/org/springframework/cloud/function/core/MonoToFluxFunction.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -22,21 +22,20 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; /** - * Marker wrapper for target Function<Mono, Flux> + * Marker wrapper for target Function<Mono, Flux>. * + * @param type of {@link Mono} input of the target function + * @param type of {@link Flux} output of the target function * @author Oleg Zhurakousky * @since 2.0 - * - * @param type of {@link Mono} input of the target function - * @param type of {@link Flux} output of the target function */ -public class MonoToFluxFunction implements Function, Flux>, FluxWrapper, Flux>> { +public class MonoToFluxFunction + implements Function, Flux>, FluxWrapper, Flux>> { private final Function, Flux> function; /** * @param function target function - * @param names name(s) of the target function (optional) */ public MonoToFluxFunction(Function, Flux> function) { this.function = function; @@ -44,11 +43,12 @@ public class MonoToFluxFunction implements Function, Flux>, Flux @Override public Function, Flux> getTarget() { - return function; + return this.function; } @Override public Flux apply(Mono input) { - return function.apply(input); + return this.function.apply(input); } + } diff --git a/spring-cloud-function-dependencies/pom.xml b/spring-cloud-function-dependencies/pom.xml index 0fdb59bdf..b8852112f 100644 --- a/spring-cloud-function-dependencies/pom.xml +++ b/spring-cloud-function-dependencies/pom.xml @@ -1,6 +1,6 @@ - 4.0.0 diff --git a/spring-cloud-function-deployer/pom.xml b/spring-cloud-function-deployer/pom.xml index cfed550f1..317264fe4 100644 --- a/spring-cloud-function-deployer/pom.xml +++ b/spring-cloud-function-deployer/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-cloud-function-deployer @@ -79,7 +79,8 @@ maven-invoker-plugin 3.0.1 - ${project.build.directory}/local-repo + ${project.build.directory}/local-repo + @@ -89,7 +90,8 @@ run - ${project.build.directory}/it + ${project.build.directory}/it + src/it/settings.xml true true diff --git a/spring-cloud-function-deployer/src/it/flux/pom.xml b/spring-cloud-function-deployer/src/it/flux/pom.xml index 402a04c06..09097ca32 100644 --- a/spring-cloud-function-deployer/src/it/flux/pom.xml +++ b/spring-cloud-function-deployer/src/it/flux/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 com.example @@ -12,12 +13,13 @@ org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE - + 1.8 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + 1.0.17.RELEASE diff --git a/spring-cloud-function-deployer/src/it/flux/src/main/java/com/example/functions/FunctionApp.java b/spring-cloud-function-deployer/src/it/flux/src/main/java/com/example/functions/FunctionApp.java index 2c873c706..49027f88a 100644 --- a/spring-cloud-function-deployer/src/it/flux/src/main/java/com/example/functions/FunctionApp.java +++ b/spring-cloud-function-deployer/src/it/flux/src/main/java/com/example/functions/FunctionApp.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -18,26 +18,27 @@ package com.example.functions; import java.util.function.Function; +import reactor.core.publisher.Flux; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -import reactor.core.publisher.Flux; - /** * @author Dave Syer */ @SpringBootApplication public class FunctionApp { - + + public static void main(String[] args) throws Exception { + SpringApplication.run(FunctionApp.class, args); + } + @Bean public Function, Flux> foos() { return flux -> flux.map(value -> new Foo(value.getValue().toUpperCase())); } - public static void main(String[] args) throws Exception { - SpringApplication.run(FunctionApp.class, args); - } } class Foo { @@ -64,4 +65,4 @@ class Foo { return "Foo [value=" + this.value + "]"; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-deployer/src/it/support/pom.xml b/spring-cloud-function-deployer/src/it/support/pom.xml index 10cce43bc..05d2a447e 100644 --- a/spring-cloud-function-deployer/src/it/support/pom.xml +++ b/spring-cloud-function-deployer/src/it/support/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 com.example @@ -12,12 +13,13 @@ org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE - + 1.8 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + 1.0.17.RELEASE diff --git a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/DoubleLogger.java b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/DoubleLogger.java index feb1c616e..cfbaf39ca 100644 --- a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/DoubleLogger.java +++ b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/DoubleLogger.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -24,4 +24,5 @@ public class DoubleLogger implements Consumer { public void accept(Integer i) { System.out.println(2 * i); } + } diff --git a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/Emitter.java b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/Emitter.java index bafe64cf1..9b1d4a1ee 100644 --- a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/Emitter.java +++ b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/Emitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -25,10 +25,11 @@ public class Emitter implements Supplier { private int i = 0; - private String[] values = {"one", "two", "three", "four"}; + private String[] values = { "one", "two", "three", "four" }; @Override public String get() { return values[i++ % values.length]; } + } diff --git a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/FunctionApp.java b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/FunctionApp.java index f3f56cc51..92a279c29 100644 --- a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/FunctionApp.java +++ b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/FunctionApp.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -25,7 +25,11 @@ import org.springframework.context.annotation.Bean; */ @SpringBootApplication public class FunctionApp { - + + public static void main(String[] args) throws Exception { + SpringApplication.run(FunctionApp.class, args); + } + @Bean public DoubleLogger myDoubler() { return new DoubleLogger(); @@ -41,7 +45,4 @@ public class FunctionApp { return new LengthCounter(); } - public static void main(String[] args) throws Exception { - SpringApplication.run(FunctionApp.class, args); - } } diff --git a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/LengthCounter.java b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/LengthCounter.java index a3eb4c38f..ff6170a0d 100644 --- a/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/LengthCounter.java +++ b/spring-cloud-function-deployer/src/it/support/src/main/java/com/example/functions/LengthCounter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -27,4 +27,5 @@ public class LengthCounter implements Function { public Integer apply(String string) { return string.length(); } + } diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationBootstrap.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationBootstrap.java index 1affd8359..209ce0d40 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationBootstrap.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2012-2019 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. @@ -45,13 +45,23 @@ import org.springframework.util.StringUtils; public class ApplicationBootstrap { private static Log logger = LogFactory.getLog(ApplicationBootstrap.class); + private ApplicationRunner runner; + private URLClassLoader classLoader; + private static boolean isolated(String[] args) { + for (String arg : args) { + if (arg.equals("--function.runner.isolated=false")) { + return false; + } + } + return true; + } + /** * Run the provided main class as a Spring Boot application with the provided command * line arguments. - * * @param mainClass the main class * @param args the command line arguments */ @@ -104,15 +114,6 @@ public class ApplicationBootstrap { return this.runner; } - private static boolean isolated(String[] args) { - for (String arg : args) { - if (arg.equals("--function.runner.isolated=false")) { - return false; - } - } - return true; - } - private URLClassLoader createClassLoader(Class mainClass) { URL[] urls = findClassPath(mainClass); if (urls.length == 1) { @@ -141,7 +142,6 @@ public class ApplicationBootstrap { return new URLClassLoader(child.toArray(new URL[0]), base); } - private URL[] findClassPath(Class mainClass) { ClassLoader base = mainClass.getClassLoader(); if (!(base instanceof URLClassLoader)) { @@ -200,4 +200,5 @@ public class ApplicationBootstrap { } return null; } + } diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java index f95c7ec17..b8949f703 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ApplicationRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2012-2019 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. @@ -52,12 +52,12 @@ public class ApplicationRunner { private final String source; - private StandardEvaluationContext app; - private final SpelParserConfiguration config; private final StandardTypeLocator typeLocator; + private StandardEvaluationContext app; + public ApplicationRunner(ClassLoader classLoader, String source) { this.classLoader = classLoader; this.source = source; @@ -70,7 +70,8 @@ public class ApplicationRunner { try { ClassUtils.overrideThreadContextClassLoader(this.classLoader); Class cls = this.classLoader.loadClass(ContextRunner.class.getName()); - this.app = new StandardEvaluationContext(cls.getDeclaredConstructor().newInstance()); + this.app = new StandardEvaluationContext( + cls.getDeclaredConstructor().newInstance()); this.app.setTypeLocator(new StandardTypeLocator(this.classLoader)); runContext(this.source, defaultProperties(UUID.randomUUID().toString()), args); @@ -148,8 +149,8 @@ public class ApplicationRunner { } /** - * List the bean names in the application context for a given type (by its fully qualified name). - * + * List the bean names in the application context for a given type (by its fully + * qualified name). * @param type the name of the type (Class) * @return the bean names of that type */ diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ContextRunner.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ContextRunner.java index b510ed013..14ee264a4 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ContextRunner.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/ContextRunner.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -32,17 +32,31 @@ import org.springframework.util.ReflectionUtils; /** * Utility class for starting a Spring Boot application in a separate thread. Best used * from an isolated class loader, e.g. through {@link ApplicationRunner}. - * + * * @author Dave Syer */ public class ContextRunner { private ConfigurableApplicationContext context; + private Thread runThread; + private volatile boolean running = false; + private Throwable error; + private long timeout = 120000; + private static boolean isFunctional(StandardEnvironment environment) { + if (!ClassUtils.isPresent( + "org.springframework.cloud.function.context.FunctionalSpringApplication", + null)) { + return false; + } + return environment.resolvePlaceholders("${spring.functional.enabled:true}") + .equals("true"); + } + public void run(final String source, final Map properties, final String... args) { // Run in new thread to ensure that the context classloader is setup @@ -59,21 +73,21 @@ public class ContextRunner { environment.getPropertySources().addFirst( new SimpleCommandLinePropertySource("args", args)); } - running = true; + ContextRunner.this.running = true; Class sourceClass = ClassUtils.resolveClassName(source, null); SpringApplication builder = builder(sourceClass, environment); - context = builder.run(args); + ContextRunner.this.context = builder.run(args); } catch (Throwable ex) { - error = ex; + ContextRunner.this.error = ex; } } }); this.runThread.start(); try { - this.runThread.join(timeout); - this.running = context != null && context.isRunning(); + this.runThread.join(this.timeout); + this.running = this.context != null && this.context.isRunning(); } catch (InterruptedException e) { this.running = false; @@ -114,7 +128,7 @@ public class ContextRunner { } public boolean isRunning() { - return running; + return this.running; } public Throwable getError() { @@ -134,21 +148,12 @@ public class ContextRunner { return application; } - private static boolean isFunctional(StandardEnvironment environment) { - if (!ClassUtils.isPresent( - "org.springframework.cloud.function.context.FunctionalSpringApplication", - null)) { - return false; - } - return environment.resolvePlaceholders("${spring.functional.enabled:true}") - .equals("true"); - } - private static class FunctionalSpringApplicationCreator { public static SpringApplication create(Class type) { return new FunctionalSpringApplication(type); } - + } + } diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/EnableFunctionDeployer.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/EnableFunctionDeployer.java index 355b0a296..e14721163 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/EnableFunctionDeployer.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/EnableFunctionDeployer.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.deployer; import java.lang.annotation.Documented; @@ -26,7 +27,6 @@ import org.springframework.context.annotation.Import; /** * Annotation to be used on a Spring Boot application if it wants to deploy a jar file * containing a function definition. - * * @author Dave Syer * */ @@ -36,4 +36,4 @@ import org.springframework.context.annotation.Import; @Import(FunctionDeployerConfiguration.class) public @interface EnableFunctionDeployer { -} \ No newline at end of file +} diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionApplication.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionApplication.java index 0d58bb3d6..b285eba3d 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionApplication.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.io.IOException; import org.springframework.boot.autoconfigure.SpringBootApplication; +// @checkstyle:off /** * @author Mark Fisher * @author Dave Syer @@ -33,3 +34,4 @@ public class FunctionApplication { } } +// @checkstyle:on diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java index 209f47ac1..4d03bd86d 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionCreatorConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2012-2019 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. @@ -42,6 +42,7 @@ import javax.annotation.PreDestroy; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; @@ -112,24 +113,25 @@ class FunctionCreatorConfiguration { */ @PostConstruct public void init() { - URL[] urls = Arrays.stream(properties.getLocation()) - .flatMap(toResourceURL(delegatingResourceLoader)).toArray(URL[]::new); - URL[] roots = Arrays.stream(properties.getLocation()).map(this::toUrl) + URL[] urls = Arrays.stream(this.properties.getLocation()) + .flatMap(toResourceURL(this.delegatingResourceLoader)) + .toArray(URL[]::new); + URL[] roots = Arrays.stream(this.properties.getLocation()).map(this::toUrl) .toArray(URL[]::new); try { - logger.info( - "Locating function from " + Arrays.asList(properties.getLocation())); + logger.info("Locating function from " + + Arrays.asList(this.properties.getLocation())); this.creator = new BeanCreator(roots, urls); - this.creator.run(properties.getMain()); + this.creator.run(this.properties.getMain()); Arrays.stream(functionNames()).map(this.creator::create).sequential() .forEach(this.creator::register); - if (properties.getName().contains("|")) { + if (this.properties.getName().contains("|")) { // A composite function has to be explicitly registered before it is // looked up because we are using the SingleEntryFunctionRegistry - this.registry.lookup(Consumer.class, properties.getName()); - this.registry.lookup(Function.class, properties.getName()); - this.registry.lookup(Supplier.class, properties.getName()); + this.registry.lookup(Consumer.class, this.properties.getName()); + this.registry.lookup(Function.class, this.properties.getName()); + this.registry.lookup(Supplier.class, this.properties.getName()); } } catch (Exception e) { @@ -150,8 +152,8 @@ class FunctionCreatorConfiguration { } private String[] functionNames() { - if (properties.getBean() != null && properties.getBean().length > 0) { - return properties.getBean(); + if (this.properties.getBean() != null && this.properties.getBean().length > 0) { + return this.properties.getBean(); } return this.creator.getFunctionNames(); } @@ -207,9 +209,78 @@ class FunctionCreatorConfiguration { return urls.toArray(new URL[urls.size()]); } + private static final class BeanCreatorClassLoader extends URLClassLoader { + + private BeanCreatorClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + @Override + protected Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + try { + if (name.startsWith("javax.") && JavaVersion.getJavaVersion() + .isEqualOrNewerThan(JavaVersion.NINE)) { + return getClass().getClassLoader().loadClass(name); + } + return super.loadClass(name, resolve); + } + catch (ClassNotFoundException e) { + if (name.contains(ContextRunner.class.getName()) + || name.contains(PostConstruct.class.getName())) { + // Special case for the ContextRunner. We can re-use the bytes for it, + // and the function jar doesn't have to include them since it is only + // used here. + byte[] bytes; + try { + bytes = StreamUtils.copyToByteArray( + getClass().getClassLoader().getResourceAsStream( + ClassUtils.convertClassNameToResourcePath(name) + + ".class")); + return defineClass(name, bytes, 0, bytes.length); + } + catch (IOException ex) { + throw new ClassNotFoundException( + "Cannot find runner class: " + name, ex); + } + } + throw e; + } + } + + } + + @Configuration + protected static class SingleEntryConfiguration implements BeanPostProcessor { + + @Autowired + private Environment env; + + @Override + public Object postProcessBeforeInitialization(Object bean, String beanName) + throws BeansException { + return bean; + } + + @Override + public Object postProcessAfterInitialization(Object bean, String beanName) + throws BeansException { + if (bean instanceof FunctionRegistry) { + String name = FunctionProperties + .functionName(this.env.getProperty("function.bean", "")); + if (name.contains("|")) { + // A single composite function with an empty name + bean = new SingleEntryFunctionRegistry((FunctionRegistry) bean, name); + } + } + return bean; + } + + } + private class ComputeLauncher extends JarLauncher { - public ComputeLauncher(Archive archive) { + ComputeLauncher(Archive archive) { super(archive); } @@ -220,9 +291,10 @@ class FunctionCreatorConfiguration { if (manifest != null) { String functionClass = manifest.getMainAttributes() .getValue("Function-Class"); - if (StringUtils.hasText(functionClass) - && ObjectUtils.isEmpty(properties.getBean())) { - properties.setBean(new String[] { functionClass }); + if (StringUtils.hasText(functionClass) && ObjectUtils.isEmpty( + FunctionCreatorConfiguration.this.properties.getBean())) { + FunctionCreatorConfiguration.this.properties + .setBean(new String[] { functionClass }); } mainClass = manifest.getMainAttributes().getValue("Start-Class"); if (mainClass == null @@ -287,6 +359,7 @@ class FunctionCreatorConfiguration { } return null; } + } /** @@ -303,8 +376,9 @@ class FunctionCreatorConfiguration { private String defaultMain; - public BeanCreator(URL[] roots, URL[] urls) { - functionClassLoader = new BeanCreatorClassLoader(expand(urls), getParent()); + BeanCreator(URL[] roots, URL[] urls) { + FunctionCreatorConfiguration.this.functionClassLoader = new BeanCreatorClassLoader( + expand(urls), getParent()); this.defaultMain = findMain(roots); } @@ -329,8 +403,7 @@ class FunctionCreatorConfiguration { File file = ResourceUtils.getFile(url); if (file.exists()) { Archive archive = file.getName().endsWith(".jar") - ? new JarFileArchive(file) - : new ExplodedArchive(file); + ? new JarFileArchive(file) : new ExplodedArchive(file); String main = new ComputeLauncher(archive).getMainClass(); if (main != null) { return main; @@ -388,13 +461,14 @@ class FunctionCreatorConfiguration { return; } if (ClassUtils.isPresent(SpringApplication.class.getName(), - functionClassLoader)) { + FunctionCreatorConfiguration.this.functionClassLoader)) { logger.info("SpringApplication available. Bootstrapping: " + main); ClassLoader contextClassLoader = ClassUtils - .overrideThreadContextClassLoader(functionClassLoader); + .overrideThreadContextClassLoader( + FunctionCreatorConfiguration.this.functionClassLoader); try { - ApplicationRunner runner = new ApplicationRunner(functionClassLoader, - main); + ApplicationRunner runner = new ApplicationRunner( + FunctionCreatorConfiguration.this.functionClassLoader, main); // TODO: make the runtime properties configurable runner.run("--spring.main.webEnvironment=false", "--spring.cloud.stream.enabled=false", @@ -416,8 +490,8 @@ class FunctionCreatorConfiguration { public String[] getFunctionNames() { Set list = new LinkedHashSet<>(); - ClassLoader contextClassLoader = ClassUtils - .overrideThreadContextClassLoader(functionClassLoader); + ClassLoader contextClassLoader = ClassUtils.overrideThreadContextClassLoader( + FunctionCreatorConfiguration.this.functionClassLoader); try { if (this.runner.containsBean(FunctionCatalog.class.getName())) { Object catalog = this.runner.getBean(FunctionCatalog.class.getName()); @@ -447,9 +521,10 @@ class FunctionCreatorConfiguration { } public Object create(String type) { - ClassLoader contextClassLoader = ClassUtils - .overrideThreadContextClassLoader(functionClassLoader); - AutowireCapableBeanFactory factory = context.getAutowireCapableBeanFactory(); + ClassLoader contextClassLoader = ClassUtils.overrideThreadContextClassLoader( + FunctionCreatorConfiguration.this.functionClassLoader); + AutowireCapableBeanFactory factory = FunctionCreatorConfiguration.this.context + .getAutowireCapableBeanFactory(); try { Object result = null; if (this.runner != null) { @@ -483,9 +558,10 @@ class FunctionCreatorConfiguration { } if (result == null) { logger.info("No bean found. Instantiating: " + type); - if (ClassUtils.isPresent(type, functionClassLoader)) { - result = factory.createBean( - ClassUtils.resolveClassName(type, functionClassLoader)); + if (ClassUtils.isPresent(type, + FunctionCreatorConfiguration.this.functionClassLoader)) { + result = factory.createBean(ClassUtils.resolveClassName(type, + FunctionCreatorConfiguration.this.functionClassLoader)); } } if (result != null) { @@ -503,7 +579,8 @@ class FunctionCreatorConfiguration { return; } FunctionRegistration registration = new FunctionRegistration( - bean, FunctionProperties.functionName(counter.getAndIncrement())); + bean, + FunctionProperties.functionName(this.counter.getAndIncrement())); if (this.runner != null) { if (this.runner.containsBean(FunctionInspector.class.getName())) { Object inspector = this.runner @@ -533,7 +610,7 @@ class FunctionCreatorConfiguration { registration.type(FunctionType.of(bean.getClass()).getType()); } registration.target(bean); - registry.register(registration); + FunctionCreatorConfiguration.this.registry.register(registration); } private Class findType(String method, Object inspector, Object bean) { @@ -549,69 +626,4 @@ class FunctionCreatorConfiguration { } - private static final class BeanCreatorClassLoader extends URLClassLoader { - private BeanCreatorClassLoader(URL[] urls, ClassLoader parent) { - super(urls, parent); - } - - @Override - protected Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - try { - if (name.startsWith("javax.") && JavaVersion.getJavaVersion().isEqualOrNewerThan(JavaVersion.NINE)) { - return getClass().getClassLoader().loadClass(name); - } - return super.loadClass(name, resolve); - } - catch (ClassNotFoundException e) { - if (name.contains(ContextRunner.class.getName()) - || name.contains(PostConstruct.class.getName())) { - // Special case for the ContextRunner. We can re-use the bytes for it, - // and the function jar doesn't have to include them since it is only - // used here. - byte[] bytes; - try { - bytes = StreamUtils.copyToByteArray( - getClass().getClassLoader().getResourceAsStream( - ClassUtils.convertClassNameToResourcePath(name) - + ".class")); - return defineClass(name, bytes, 0, bytes.length); - } - catch (IOException ex) { - throw new ClassNotFoundException( - "Cannot find runner class: " + name, ex); - } - } - throw e; - } - } - } - - @Configuration - protected static class SingleEntryConfiguration implements BeanPostProcessor { - - @Autowired - private Environment env; - - @Override - public Object postProcessBeforeInitialization(Object bean, String beanName) - throws BeansException { - return bean; - } - - @Override - public Object postProcessAfterInitialization(Object bean, String beanName) - throws BeansException { - if (bean instanceof FunctionRegistry) { - String name = FunctionProperties - .functionName(env.getProperty("function.bean", "")); - if (name.contains("|")) { - // A single composite function with an empty name - bean = new SingleEntryFunctionRegistry((FunctionRegistry) bean, name); - } - } - return bean; - } - - } } diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java index f4749a167..5fbbf5646 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionDeployerConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.deployer; import java.util.HashMap; diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java index 39532752a..7a9ec76f8 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/FunctionProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -42,38 +42,10 @@ public class FunctionProperties { private String[] bean = new String[0]; /** - * Optional main class from which to build a Spring application context + * Optional main class from which to build a Spring application context. */ private String main; - public String getName() { - return functionName(StringUtils.arrayToDelimitedString(bean, ",")); - } - - public String[] getBean() { - return bean; - } - - public void setBean(String[] bean) { - this.bean = bean; - } - - public String[] getLocation() { - return location; - } - - public void setLocation(String[] location) { - this.location = location; - } - - public String getMain() { - return main; - } - - public void setMain(String main) { - this.main = main; - } - public static String functionName(String name) { if (!name.contains(",")) { return "function0"; @@ -89,11 +61,40 @@ public class FunctionProperties { return "function" + value; } + public String getName() { + return functionName(StringUtils.arrayToDelimitedString(this.bean, ",")); + } + + public String[] getBean() { + return this.bean; + } + + public void setBean(String[] bean) { + this.bean = bean; + } + + public String[] getLocation() { + return this.location; + } + + public void setLocation(String[] location) { + this.location = location; + } + + public String getMain() { + return this.main; + } + + public void setMain(String main) { + this.main = main; + } + @PostConstruct public void init() { - if (location.length == 0) { + if (this.location.length == 0) { throw new IllegalStateException( "No archive location provided, please configure function.location as a jar or directory."); } } + } diff --git a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistry.java b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistry.java index 81cc3ebe4..031dc9f67 100644 --- a/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistry.java +++ b/spring-cloud-function-deployer/src/main/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.deployer; import java.util.Collections; @@ -40,12 +41,13 @@ public class SingleEntryFunctionRegistry implements FunctionRegistry { @Override public T lookup(Class type, String name) { if (StringUtils.isEmpty(name)) { - if (delegate.getNames(type).size() == 1) { - return delegate.lookup(type, delegate.getNames(type).iterator().next()); + if (this.delegate.getNames(type).size() == 1) { + return this.delegate.lookup(type, + this.delegate.getNames(type).iterator().next()); } name = this.name; } - return name.equals(this.name) ? delegate.lookup(type, name) : null; + return name.equals(this.name) ? this.delegate.lookup(type, name) : null; } @Override diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/AdhocTestSuite.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/AdhocTestSuite.java index c7f0d5737..8c2c0b3db 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/AdhocTestSuite.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/AdhocTestSuite.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java index c5af0a853..816e613e0 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ApplicationRunnerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -52,4 +52,5 @@ public class ApplicationRunnerTests { assertThat(runner.getBeanNames(FunctionRegistration.class.getName())).hasSize(2); runner.close(); } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ContextRunnerTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ContextRunnerTests.java index a3e3a7a59..c1ad41231 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ContextRunnerTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/ContextRunnerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -37,4 +37,5 @@ public class ContextRunnerTests { assertThat(runner.getContext()).isNotNull(); runner.close(); } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionCreatorConfigurationTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionCreatorConfigurationTests.java index 99f81ecfc..dd336589d 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionCreatorConfigurationTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/FunctionCreatorConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2012-2019-2018 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. @@ -22,6 +22,8 @@ import java.util.function.Supplier; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -35,9 +37,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - @RunWith(SpringRunner.class) @SpringBootTest(classes = { FunctionDeployerConfiguration.class }) @DirtiesContext @@ -53,10 +52,11 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testDouble() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4); } + } @EnableAutoConfiguration @@ -68,10 +68,11 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testDouble() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4); } + } @EnableAutoConfiguration @@ -84,10 +85,11 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testDouble() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4); } + } @EnableAutoConfiguration @@ -100,7 +102,7 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testDouble() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4); } @@ -117,10 +119,11 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testFrenchize() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo("deux"); } + } @EnableAutoConfiguration @@ -133,10 +136,11 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testDouble() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4); } + } @EnableAutoConfiguration @@ -147,10 +151,11 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testDouble() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo(4); } + } @EnableAutoConfiguration @@ -162,13 +167,13 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testSupplier() { - Supplier function = catalog.lookup(Supplier.class, "function0"); + Supplier function = this.catalog.lookup(Supplier.class, "function0"); assertThat(function).isNull(); } @Test public void testFunction() { - Supplier> function = catalog.lookup(Supplier.class, + Supplier> function = this.catalog.lookup(Supplier.class, "function0|function1"); assertThat(function.get().blockFirst()).isEqualTo("un"); } @@ -184,17 +189,18 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testFunction() { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0|function1"); assertThat(function.apply(Flux.just(2)).blockFirst()).isEqualTo("quatre"); } @Test public void testThen() { - Function function = catalog.lookup(Function.class, + Function function = this.catalog.lookup(Function.class, "function1"); assertThat(function).isNull(); } + } @EnableAutoConfiguration @@ -209,10 +215,12 @@ public abstract class FunctionCreatorConfigurationTests { @Test public void testConsumer() { - Function, Mono> function = catalog.lookup(Function.class, - "function0|function1"); + Function, Mono> function = this.catalog + .lookup(Function.class, "function0|function1"); function.apply(Flux.just(2)).block(); - capture.expect(containsString("Seen deux")); + this.capture.expect(containsString("Seen deux")); } + } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistryTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistryTests.java index 679ad9712..4305c34e2 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistryTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SingleEntryFunctionRegistryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -34,33 +34,33 @@ public class SingleEntryFunctionRegistryTests { @Test public void named() { - delegate.register(new FunctionRegistration(new Foos(), "foo")); - SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry(delegate, - "foo"); + this.delegate.register(new FunctionRegistration(new Foos(), "foo")); + SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry( + this.delegate, "foo"); assertThat((Foos) registry.lookup("foo")).isInstanceOf(Function.class); } @Test public void other() { - delegate.register(new FunctionRegistration(new Foos(), "foo")); - SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry(delegate, - "foo"); + this.delegate.register(new FunctionRegistration(new Foos(), "foo")); + SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry( + this.delegate, "foo"); assertThat((Foos) registry.lookup("bar")).isNull(); } @Test public void empty() { - delegate.register(new FunctionRegistration(new Foos(), "")); - SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry(delegate, - ""); + this.delegate.register(new FunctionRegistration(new Foos(), "")); + SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry( + this.delegate, ""); assertThat((Foos) registry.lookup("")).isInstanceOf(Function.class); } @Test public void anonymous() { - delegate.register(new FunctionRegistration(new Foos(), "bar")); - SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry(delegate, - "foo"); + this.delegate.register(new FunctionRegistration(new Foos(), "bar")); + SingleEntryFunctionRegistry registry = new SingleEntryFunctionRegistry( + this.delegate, "foo"); assertThat((Foos) registry.lookup("")).isInstanceOf(Function.class); } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppConfigurationTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppConfigurationTests.java index 1b34fd23a..13187eae4 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppConfigurationTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,8 @@ import java.util.function.Supplier; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -34,9 +36,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - @RunWith(SpringRunner.class) @SpringBootTest(classes = FunctionDeployerConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) @TestPropertySource(properties = { @@ -53,7 +52,8 @@ public abstract class SpringFunctionAppConfigurationTests { @Test public void test() throws Exception { - Supplier> function = catalog.lookup(Supplier.class, "function0"); + Supplier> function = this.catalog.lookup(Supplier.class, + "function0"); assertThat(function.get().blockFirst()).isEqualTo("one"); } @@ -65,7 +65,7 @@ public abstract class SpringFunctionAppConfigurationTests { @Test public void test() throws Exception { - Supplier> function = catalog.lookup(Supplier.class, + Supplier> function = this.catalog.lookup(Supplier.class, "function0|function1"); assertThat(function.get().blockFirst()).isEqualTo(3); } @@ -78,7 +78,7 @@ public abstract class SpringFunctionAppConfigurationTests { @Test public void test() throws Exception { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just("spam")).blockFirst()).isEqualTo(4); } @@ -95,12 +95,12 @@ public abstract class SpringFunctionAppConfigurationTests { @Test public void test() throws Exception { // Can't assert side effects. - Function, Mono> function = catalog.lookup(Function.class, - "function0"); + Function, Mono> function = this.catalog + .lookup(Function.class, "function0"); function.apply(Flux.just(5)).block(); - capture.expect(containsString(String.format("10%n"))); + this.capture.expect(containsString(String.format("10%n"))); } } -} \ No newline at end of file +} diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppExplodedConfigurationTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppExplodedConfigurationTests.java index 7926ec9ea..296443efe 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppExplodedConfigurationTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionAppExplodedConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,8 @@ import java.util.function.Supplier; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -34,9 +36,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; import static org.hamcrest.Matchers.containsString; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - @RunWith(SpringRunner.class) @SpringBootTest(classes = FunctionDeployerConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.NONE) @TestPropertySource(properties = { @@ -53,7 +52,8 @@ public abstract class SpringFunctionAppExplodedConfigurationTests { @Test public void test() throws Exception { - Supplier> function = catalog.lookup(Supplier.class, "function0"); + Supplier> function = this.catalog.lookup(Supplier.class, + "function0"); assertThat(function.get().blockFirst()).isEqualTo("one"); } @@ -61,11 +61,12 @@ public abstract class SpringFunctionAppExplodedConfigurationTests { @EnableAutoConfiguration @TestPropertySource(properties = { "function.bean=myEmitter,myCounter" }) - public static class CompositeTests extends SpringFunctionAppExplodedConfigurationTests { + public static class CompositeTests + extends SpringFunctionAppExplodedConfigurationTests { @Test public void test() throws Exception { - Supplier> function = catalog.lookup(Supplier.class, + Supplier> function = this.catalog.lookup(Supplier.class, "function0|function1"); assertThat(function.get().blockFirst()).isEqualTo(3); } @@ -74,11 +75,12 @@ public abstract class SpringFunctionAppExplodedConfigurationTests { @EnableAutoConfiguration @TestPropertySource(properties = { "function.bean=myCounter" }) - public static class ProcessorTests extends SpringFunctionAppExplodedConfigurationTests { + public static class ProcessorTests + extends SpringFunctionAppExplodedConfigurationTests { @Test public void test() throws Exception { - Function, Flux> function = catalog + Function, Flux> function = this.catalog .lookup(Function.class, "function0"); assertThat(function.apply(Flux.just("spam")).blockFirst()).isEqualTo(4); } @@ -95,12 +97,12 @@ public abstract class SpringFunctionAppExplodedConfigurationTests { @Test public void test() throws Exception { // Can't assert side effects. - Function, Mono> function = catalog.lookup(Function.class, - "function0"); + Function, Mono> function = this.catalog + .lookup(Function.class, "function0"); function.apply(Flux.just(5)).block(); - capture.expect(containsString(String.format("10%n"))); + this.capture.expect(containsString(String.format("10%n"))); } } -} \ No newline at end of file +} diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionFluxConfigurationTests.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionFluxConfigurationTests.java index 6ff50346c..818efcabb 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionFluxConfigurationTests.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/deployer/SpringFunctionFluxConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2019 the original author or authors. + * Copyright 2012-2019 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. @@ -44,39 +44,42 @@ public class SpringFunctionFluxConfigurationTests { @Before public void run() { - if (bootstrap == null) { - bootstrap = new ApplicationBootstrap(); - bootstrap.run(SpringFunctionFluxConfigurationTests.class, + if (this.bootstrap == null) { + this.bootstrap = new ApplicationBootstrap(); + this.bootstrap.run(SpringFunctionFluxConfigurationTests.class, "--function.location=file:target/it/flux/target/dependency", "--function.bean=foos", "--function.main=com.example.functions.FunctionApp"); - catalog = bootstrap.getRunner().getBean(FunctionCatalog.class.getName()); - inspector = bootstrap.getRunner().getBean(FunctionInspector.class.getName()); + this.catalog = this.bootstrap.getRunner() + .getBean(FunctionCatalog.class.getName()); + this.inspector = this.bootstrap.getRunner() + .getBean(FunctionInspector.class.getName()); } } @After public void close() { - if (bootstrap != null) { - bootstrap.close(); + if (this.bootstrap != null) { + this.bootstrap.close(); } } @Test public void test() throws Exception { @SuppressWarnings("unchecked") - Function function = (Function) bootstrap + Function function = (Function) this.bootstrap .getRunner() - .evaluate("lookup(T(java.util.function.Function), 'function0')", catalog); + .evaluate("lookup(T(java.util.function.Function), 'function0')", + this.catalog); assertThat(function).isNotNull(); - Class inputType = (Class) bootstrap.getRunner() - .evaluate("getInputType(#function)", inspector, "function", function); + Class inputType = (Class) this.bootstrap.getRunner().evaluate( + "getInputType(#function)", this.inspector, "function", function); assertThat(inputType.getName()).isEqualTo("com.example.functions.Foo"); Object foo = create(inputType); - Class outputType = (Class) bootstrap.getRunner() - .evaluate("getOutputType(#function)", inspector, "function", function); + Class outputType = (Class) this.bootstrap.getRunner().evaluate( + "getOutputType(#function)", this.inspector, "function", function); assertThat(outputType.getName()).isEqualTo("com.example.functions.Foo"); - String value = (String) bootstrap.getRunner().evaluate( + String value = (String) this.bootstrap.getRunner().evaluate( "apply(T(reactor.core.publisher.Flux).just(#foo)).blockFirst().getValue()", function, "foo", foo); assertThat(value).isEqualTo("FOO"); @@ -115,4 +118,4 @@ class Foo { return "Foo [value=" + this.value + "]"; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Doubler.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Doubler.java index bd5310951..6884f24ef 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Doubler.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Doubler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,8 +19,10 @@ package org.springframework.cloud.function.test; import java.util.function.Function; public class Doubler implements Function { + @Override public Integer apply(Integer integer) { return 2 * integer; } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Frenchizer.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Frenchizer.java index 7c9eb3fbd..8ab417afa 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Frenchizer.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Frenchizer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -27,10 +27,10 @@ public class Frenchizer implements Function { @PostConstruct public void init() { this.numbers = new String[4]; - numbers[0] = "un"; - numbers[1] = "deux"; - numbers[2] = "trois"; - numbers[3] = "quatre"; + this.numbers[0] = "un"; + this.numbers[1] = "deux"; + this.numbers[2] = "trois"; + this.numbers[3] = "quatre"; } @Override @@ -40,4 +40,5 @@ public class Frenchizer implements Function { } throw new RuntimeException(); } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionApp.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionApp.java index d0972702e..731799fe9 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionApp.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionApp.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -26,6 +26,10 @@ import org.springframework.context.annotation.Bean; @SpringBootConfiguration public class FunctionApp { + public static void main(String[] args) throws Exception { + SpringApplication.run(FunctionApp.class, args); + } + @Bean public Doubler myDoubler() { return new Doubler(); @@ -36,7 +40,4 @@ public class FunctionApp { return new Frenchizer(); } - public static void main(String[] args) throws Exception { - SpringApplication.run(FunctionApp.class, args); - } } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionInitializer.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionInitializer.java index ea5880fab..e4cb5a1b2 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionInitializer.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -28,6 +28,12 @@ import org.springframework.context.support.GenericApplicationContext; public class FunctionInitializer implements ApplicationContextInitializer { + public static void main(String[] args) throws Exception { + SpringApplication application = new FunctionalSpringApplication( + FunctionInitializer.class); + application.run(args); + } + @Bean public Doubler myDoubler() { return new Doubler(); @@ -38,16 +44,11 @@ public class FunctionInitializer return new Frenchizer(); } - public static void main(String[] args) throws Exception { - SpringApplication application = new FunctionalSpringApplication( - FunctionInitializer.class); - application.run(args); - } - @Override public void initialize(GenericApplicationContext context) { // TODO: support for FunctionRegistration context.registerBean("myDoubler", Doubler.class, () -> myDoubler()); context.registerBean("myFrenchizer", Frenchizer.class, () -> myFrenchizer()); } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionRegistrar.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionRegistrar.java index 7438174ef..2f57bb7c0 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionRegistrar.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/FunctionRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -30,6 +30,12 @@ import org.springframework.context.support.GenericApplicationContext; public class FunctionRegistrar implements ApplicationContextInitializer { + public static void main(String[] args) throws Exception { + SpringApplication application = new FunctionalSpringApplication( + FunctionRegistrar.class); + application.run(args); + } + @Bean public Doubler myDoubler() { return new Doubler(); @@ -40,12 +46,6 @@ public class FunctionRegistrar return new Frenchizer(); } - public static void main(String[] args) throws Exception { - SpringApplication application = new FunctionalSpringApplication( - FunctionRegistrar.class); - application.run(args); - } - @Override public void initialize(GenericApplicationContext context) { context.registerBean("theDoubler", FunctionRegistration.class, @@ -58,4 +58,5 @@ public class FunctionRegistrar .type(FunctionType.of((Frenchizer.class))); }); } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/NumberEmitter.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/NumberEmitter.java index 2bfde2188..7e39d121b 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/NumberEmitter.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/NumberEmitter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,8 +19,10 @@ package org.springframework.cloud.function.test; import java.util.function.Supplier; public class NumberEmitter implements Supplier { + @Override public Integer get() { return 1; } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Printer.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Printer.java index 99e64502a..9690045c5 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Printer.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/Printer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -24,4 +24,5 @@ public class Printer implements Consumer { public void accept(Object o) { System.err.println("Seen " + o); } + } diff --git a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/SpringDoubler.java b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/SpringDoubler.java index 2a0d3b2fb..d3dafb571 100644 --- a/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/SpringDoubler.java +++ b/spring-cloud-function-deployer/src/test/java/org/springframework/cloud/function/test/SpringDoubler.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -35,15 +35,16 @@ public class SpringDoubler implements Function { @PostConstruct public void init() { if (this.context == null) { - context = new SpringApplicationBuilder(FunctionApp.class).bannerMode(Mode.OFF).registerShutdownHook(false) + this.context = new SpringApplicationBuilder(FunctionApp.class) + .bannerMode(Mode.OFF).registerShutdownHook(false) .web(WebApplicationType.NONE).run(); } } @PreDestroy public void close() { - if (context != null) { - context.close(); + if (this.context != null) { + this.context.close(); } } @@ -51,4 +52,5 @@ public class SpringDoubler implements Function { public Integer apply(Integer integer) { return 2 * integer; } + } diff --git a/spring-cloud-function-kotlin/pom.xml b/spring-cloud-function-kotlin/pom.xml index 93aba55da..d2f114b9d 100644 --- a/spring-cloud-function-kotlin/pom.xml +++ b/spring-cloud-function-kotlin/pom.xml @@ -1,7 +1,7 @@ - + 4.0.0 spring-cloud-function-kotlin diff --git a/spring-cloud-function-kotlin/src/main/java/org/springframework/cloud/function/context/config/KotlinLambdaToFunctionAutoConfiguration.java b/spring-cloud-function-kotlin/src/main/java/org/springframework/cloud/function/context/config/KotlinLambdaToFunctionAutoConfiguration.java index 3795bf8ba..f394debbf 100644 --- a/spring-cloud-function-kotlin/src/main/java/org/springframework/cloud/function/context/config/KotlinLambdaToFunctionAutoConfiguration.java +++ b/spring-cloud-function-kotlin/src/main/java/org/springframework/cloud/function/context/config/KotlinLambdaToFunctionAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,9 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import kotlin.Unit; +import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -36,16 +39,11 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.type.MethodMetadata; -import kotlin.Unit; -import kotlin.jvm.functions.Function0; -import kotlin.jvm.functions.Function1; - /** * Configuration class which defines the required infrastructure to bootstrap Kotlin * lambdas as invocable functions within the context of the framework. * * @author Oleg Zhurakousky - * * @since 2.0 */ @Configuration @@ -58,43 +56,65 @@ class KotlinLambdaToFunctionAutoConfiguration { * Will transform all discovered Kotlin's Function1 and Function0 lambdas to java * Supplier, Function and Consumer, retaining the original Kotlin type * characteristics. In other words the resulting bean could be cast to both java and - * kotlin types (i.e., java Function vs. kotlin Function1) + * kotlin types (i.e., java Function<I,O> vs. kotlin Function1<I,O>) + * @return the bean factory post processor */ @Bean public BeanFactoryPostProcessor kotlinToFunctionTransformer() { return new BeanFactoryPostProcessor() { @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + public void postProcessBeanFactory( + ConfigurableListableBeanFactory beanFactory) throws BeansException { String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames(); for (String beanDefinitionName : beanDefinitionNames) { - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanDefinitionName); + BeanDefinition beanDefinition = beanFactory + .getBeanDefinition(beanDefinitionName); Object source = beanDefinition.getSource(); if (source instanceof MethodMetadata) { - String returnTypeName = ((MethodMetadata)source).getReturnTypeName(); + String returnTypeName = ((MethodMetadata) source) + .getReturnTypeName(); if (returnTypeName.startsWith("kotlin.jvm.functions.Function")) { - FunctionType functionType = new FunctionType(FunctionContextUtils.findType(beanDefinitionName, beanFactory)); + FunctionType functionType = new FunctionType( + FunctionContextUtils.findType(beanDefinitionName, + beanFactory)); if (returnTypeName.equals("kotlin.jvm.functions.Function1")) { - if (Unit.class.isAssignableFrom(functionType.getOutputType())) { - logger.debug("Transforming Kotlin lambda " + beanDefinitionName + " to java Consumer"); - this.register(beanDefinitionName, beanDefinition, KotlinConsumer.class, (BeanDefinitionRegistry) beanFactory); + if (Unit.class + .isAssignableFrom(functionType.getOutputType())) { + KotlinLambdaToFunctionAutoConfiguration.this.logger + .debug("Transforming Kotlin lambda " + + beanDefinitionName + + " to java Consumer"); + this.register(beanDefinitionName, beanDefinition, + KotlinConsumer.class, + (BeanDefinitionRegistry) beanFactory); } else { - logger.debug("Transforming Kotlin lambda " + beanDefinitionName + " to java Function"); - this.register(beanDefinitionName, beanDefinition, KotlinFunction.class, (BeanDefinitionRegistry) beanFactory); + KotlinLambdaToFunctionAutoConfiguration.this.logger + .debug("Transforming Kotlin lambda " + + beanDefinitionName + + " to java Function"); + this.register(beanDefinitionName, beanDefinition, + KotlinFunction.class, + (BeanDefinitionRegistry) beanFactory); } } - else { - logger.debug("Transforming Kotlin lambda " + beanDefinitionName + " to java Supplier"); - this.register(beanDefinitionName, beanDefinition, KotlinSupplier.class, (BeanDefinitionRegistry) beanFactory); + else { + KotlinLambdaToFunctionAutoConfiguration.this.logger.debug( + "Transforming Kotlin lambda " + beanDefinitionName + + " to java Supplier"); + this.register(beanDefinitionName, beanDefinition, + KotlinSupplier.class, + (BeanDefinitionRegistry) beanFactory); } } } } } - private void register(String originalName, BeanDefinition originalDefinition, Class clazz, BeanDefinitionRegistry registry) { + private void register(String originalName, BeanDefinition originalDefinition, + Class clazz, BeanDefinitionRegistry registry) { RootBeanDefinition cbd = new RootBeanDefinition(clazz); ConstructorArgumentValues ca = new ConstructorArgumentValues(); ca.addGenericArgumentValue(originalDefinition); @@ -106,10 +126,11 @@ class KotlinLambdaToFunctionAutoConfiguration { } /** - * Wrapper for Kotlin lambda to be represented as both Java Function as well as - * Kotlin's Function1 + * Wrapper for Kotlin lambda to be represented as both Java Function<I,O> as + * well as Kotlin's Function1<I,O>. */ - private static class KotlinFunction implements Function, Function1 { + private static final class KotlinFunction + implements Function, Function1 { private final Function1 kotlinLambda; @@ -126,13 +147,15 @@ class KotlinLambdaToFunctionAutoConfiguration { public O invoke(I i) { return this.apply(i); } + } /** - * Wrapper for Kotlin lambda to be represented as both Java Consumer as well as - * Kotlin's Function1 + * Wrapper for Kotlin lambda to be represented as both Java Consumer<I> as well + * as Kotlin's Function1<I,Unit>. */ - private static class KotlinConsumer implements Consumer, Function1 { + private static final class KotlinConsumer + implements Consumer, Function1 { private final Function1 kotlinLambda; @@ -149,13 +172,14 @@ class KotlinLambdaToFunctionAutoConfiguration { public void accept(I i) { this.kotlinLambda.invoke(i); } + } /** - * Wrapper for Kotlin lambda to be represented as both Java Supplier as well as - * Kotlin's Function0 + * Wrapper for Kotlin lambda to be represented as both Java Supplier<O> as well + * as Kotlin's Function0<O>. */ - private static class KotlinSupplier implements Supplier, Function0 { + private static final class KotlinSupplier implements Supplier, Function0 { private final Function0 kotlinLambda; @@ -172,6 +196,7 @@ class KotlinLambdaToFunctionAutoConfiguration { public O invoke() { return this.kotlinLambda.invoke(); } + } } diff --git a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java index 11402667c..b83241125 100644 --- a/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java +++ b/spring-cloud-function-kotlin/src/test/java/org/springframework/cloud/function/kotlin/ContextFunctionCatalogAutoConfigurationKotlinTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -16,14 +16,16 @@ package org.springframework.cloud.function.kotlin; -import static org.assertj.core.api.Assertions.assertThat; - import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import kotlin.jvm.functions.Function0; +import kotlin.jvm.functions.Function1; import org.junit.After; import org.junit.Test; +import reactor.core.publisher.Flux; + import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.cloud.function.context.FunctionCatalog; @@ -32,9 +34,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import kotlin.jvm.functions.Function0; -import kotlin.jvm.functions.Function1; -import reactor.core.publisher.Flux; +import static org.assertj.core.api.Assertions.assertThat; /** * @author Oleg Zhurakousky @@ -42,60 +42,63 @@ import reactor.core.publisher.Flux; public class ContextFunctionCatalogAutoConfigurationKotlinTests { private ConfigurableApplicationContext context; + private FunctionCatalog catalog; + private FunctionInspector inspector; @After public void close() { - if (context != null) { - context.close(); + if (this.context != null) { + this.context.close(); } } @Test public void kotlinLambdas() { - create(new Class[] {KotlinLambdasConfiguration.class, SimpleConfiguration.class}); + create(new Class[] { KotlinLambdasConfiguration.class, + SimpleConfiguration.class }); - assertThat(context.getBean("kotlinFunction")).isInstanceOf(Function.class); - assertThat(context.getBean("kotlinFunction")).isInstanceOf(Function1.class); - assertThat((Function) catalog.lookup(Function.class, "kotlinFunction")) + assertThat(this.context.getBean("kotlinFunction")).isInstanceOf(Function.class); + assertThat(this.context.getBean("kotlinFunction")).isInstanceOf(Function1.class); + assertThat((Function) this.catalog.lookup(Function.class, "kotlinFunction")) .isInstanceOf(Function.class); - assertThat( - inspector.getInputType(catalog.lookup(Function.class, "kotlinFunction"))) + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "kotlinFunction"))) .isAssignableFrom(String.class); - assertThat( - inspector.getOutputType(catalog.lookup(Function.class, "kotlinFunction"))) + assertThat(this.inspector + .getOutputType(this.catalog.lookup(Function.class, "kotlinFunction"))) .isAssignableFrom(String.class); - assertThat(context.getBean("kotlinConsumer")).isInstanceOf(Consumer.class); - assertThat(context.getBean("kotlinConsumer")).isInstanceOf(Function1.class); - assertThat((Function) catalog.lookup(Function.class, "kotlinConsumer")) + assertThat(this.context.getBean("kotlinConsumer")).isInstanceOf(Consumer.class); + assertThat(this.context.getBean("kotlinConsumer")).isInstanceOf(Function1.class); + assertThat((Function) this.catalog.lookup(Function.class, "kotlinConsumer")) .isInstanceOf(Function.class); - assertThat( - inspector.getInputType(catalog.lookup(Function.class, "kotlinConsumer"))) + assertThat(this.inspector + .getInputType(this.catalog.lookup(Function.class, "kotlinConsumer"))) .isAssignableFrom(String.class); - assertThat(context.getBean("kotlinSupplier")).isInstanceOf(Supplier.class); - assertThat(context.getBean("kotlinSupplier")).isInstanceOf(Function0.class); - Supplier> supplier = catalog.lookup(Supplier.class, + assertThat(this.context.getBean("kotlinSupplier")).isInstanceOf(Supplier.class); + assertThat(this.context.getBean("kotlinSupplier")).isInstanceOf(Function0.class); + Supplier> supplier = this.catalog.lookup(Supplier.class, "kotlinSupplier"); assertThat(supplier.get().blockFirst()).isEqualTo("Hello"); - assertThat((Supplier) catalog.lookup(Supplier.class, "kotlinSupplier")) + assertThat((Supplier) this.catalog.lookup(Supplier.class, "kotlinSupplier")) .isInstanceOf(Supplier.class); - assertThat( - inspector.getOutputType(catalog.lookup(Supplier.class, "kotlinSupplier"))) + assertThat(this.inspector + .getOutputType(this.catalog.lookup(Supplier.class, "kotlinSupplier"))) .isAssignableFrom(String.class); - Function, Flux> function = catalog.lookup(Function.class, - "kotlinFunction|function2"); + Function, Flux> function = this.catalog + .lookup(Function.class, "kotlinFunction|function2"); assertThat(function.apply(Flux.just("Hello")).blockFirst()) .isEqualTo("HELLOfunction2"); } private void create(Class[] types, String... props) { - context = new SpringApplicationBuilder(types).properties(props).run(); - catalog = context.getBean(FunctionCatalog.class); - inspector = context.getBean(FunctionInspector.class); + this.context = new SpringApplicationBuilder(types).properties(props).run(); + this.catalog = this.context.getBean(FunctionCatalog.class); + this.inspector = this.context.getBean(FunctionInspector.class); } @EnableAutoConfiguration @@ -106,5 +109,7 @@ public class ContextFunctionCatalogAutoConfigurationKotlinTests { public Function function2() { return value -> value + "function2"; } + } + } diff --git a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt index db53c8305..4b5a1cac4 100644 --- a/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt +++ b/spring-cloud-function-kotlin/src/test/kotlin/org/springframework/cloud/function/kotlin/KotlinLambdasConfiguration.kt @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -27,18 +27,18 @@ import org.springframework.context.annotation.Configuration @EnableAutoConfiguration @Configuration open class KotlinLambdasConfiguration { - @Bean - open fun kotlinFunction(): (String) -> String { - return { it.toUpperCase() } - } + @Bean + open fun kotlinFunction(): (String) -> String { + return { it.toUpperCase() } + } - @Bean - open fun kotlinConsumer(): (String) -> Unit { - return { println(it) } - } + @Bean + open fun kotlinConsumer(): (String) -> Unit { + return { println(it) } + } - @Bean - open fun kotlinSupplier(): () -> String { - return { "Hello" } - } -} \ No newline at end of file + @Bean + open fun kotlinSupplier(): () -> String { + return { "Hello" } + } +} diff --git a/spring-cloud-function-samples/function-sample-aws/build.gradle b/spring-cloud-function-samples/function-sample-aws/build.gradle index 8a3fe0dec..312d122be 100644 --- a/spring-cloud-function-samples/function-sample-aws/build.gradle +++ b/spring-cloud-function-samples/function-sample-aws/build.gradle @@ -11,8 +11,8 @@ buildscript { maven { url "https://repo.spring.io/snapshot" } maven { url "https://repo.spring.io/milestone" } } - dependencies { - classpath "com.github.jengelman.gradle.plugins:shadow:${shadowVersion}" + dependencies { + classpath "com.github.jengelman.gradle.plugins:shadow:${shadowVersion}" classpath("org.springframework.boot.experimental:spring-boot-thin-gradle-plugin:${wrapperVersion}") classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } @@ -40,39 +40,40 @@ repositories { ext { springCloudFunctionVersion = "2.0.0.BUILD-SNAPSHOT" - awsLambdaEventsVersion = "1.2.1" - awsLambdaCoreVersion = "1.1.0" + awsLambdaEventsVersion = "1.2.1" + awsLambdaCoreVersion = "1.1.0" } ext['reactor.version'] = "3.1.7.RELEASE" assemble.dependsOn = [shadowJar, thinJar] jar { - manifest { - attributes 'Main-Class': 'example.Config' - } + manifest { + attributes 'Main-Class': 'example.Config' + } } import com.github.jengelman.gradle.plugins.shadow.transformers.* shadowJar { - classifier = 'aws' - dependencies { - exclude(dependency("org.springframework.cloud:spring-cloud-function-web:${springCloudFunctionVersion}")) - } - // Required for Spring - mergeServiceFiles() - append 'META-INF/spring.handlers' - append 'META-INF/spring.schemas' - append 'META-INF/spring.tooling' - transform(PropertiesFileTransformer) { - paths = ['META-INF/spring.factories' ] - mergeStrategy = "append" - } + classifier = 'aws' + dependencies { + exclude( + dependency("org.springframework.cloud:spring-cloud-function-web:${springCloudFunctionVersion}")) + } + // Required for Spring + mergeServiceFiles() + append 'META-INF/spring.handlers' + append 'META-INF/spring.schemas' + append 'META-INF/spring.tooling' + transform(PropertiesFileTransformer) { + paths = ['META-INF/spring.factories'] + mergeStrategy = "append" + } } configurations { - testCompile.extendsFrom(compileOnly) + testCompile.extendsFrom(compileOnly) } dependencies { diff --git a/spring-cloud-function-samples/function-sample-aws/pom.xml b/spring-cloud-function-samples/function-sample-aws/pom.xml index acdb2df5e..5b8ee07f1 100644 --- a/spring-cloud-function-samples/function-sample-aws/pom.xml +++ b/spring-cloud-function-samples/function-sample-aws/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 io.spring.sample @@ -15,7 +16,7 @@ org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE - + @@ -24,7 +25,8 @@ 1.8 1.0.17.RELEASE 2.0.2 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + example.Config diff --git a/spring-cloud-function-samples/function-sample-aws/src/main/java/example/Config.java b/spring-cloud-function-samples/function-sample-aws/src/main/java/example/Config.java index 4bb01bb7e..0b1635985 100644 --- a/spring-cloud-function-samples/function-sample-aws/src/main/java/example/Config.java +++ b/spring-cloud-function-samples/function-sample-aws/src/main/java/example/Config.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -27,6 +27,7 @@ import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.annotation.Bean; import org.springframework.context.support.GenericApplicationContext; +// @checkstyle:off @SpringBootApplication @EnableConfigurationProperties(Properties.class) public class Config implements ApplicationContextInitializer { @@ -40,14 +41,14 @@ public class Config implements ApplicationContextInitializer function() { return value -> new Bar( - value.uppercase() + (props.getFoo() != null ? "-" + props.getFoo() : "")); - } - - public static void main(String[] args) throws Exception { - FunctionalSpringApplication.run(Config.class, args); + value.uppercase() + (this.props.getFoo() != null ? "-" + this.props.getFoo() : "")); } @Override @@ -61,6 +62,7 @@ public class Config implements ApplicationContextInitializer handler = new SpringBootRequestHandler<>(Config.class); + SpringBootRequestHandler handler = new SpringBootRequestHandler<>( + Config.class); handler.handleRequest(new Foo("foo"), null); handler.close(); } diff --git a/spring-cloud-function-samples/function-sample-azure/pom.xml b/spring-cloud-function-samples/function-sample-azure/pom.xml index a18e0905b..a21cbffa1 100644 --- a/spring-cloud-function-samples/function-sample-azure/pom.xml +++ b/spring-cloud-function-samples/function-sample-azure/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 io.spring.sample @@ -14,7 +15,7 @@ org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE - + @@ -24,7 +25,8 @@ function-sample-azure westus java-function-group - ${project.build.directory}/azure-functions/${functionAppName} + ${project.build.directory}/azure-functions/${functionAppName} + example.Config 1.0.15.RELEASE @@ -92,11 +94,11 @@ azure-functions-maven-plugin 1.0.0-beta-7 - - javax.xml.bind - jaxb-api - 2.3.1 - + + javax.xml.bind + jaxb-api + 2.3.1 + @@ -168,11 +170,13 @@ true - ${project.build.directory}/azure-functions/${functionAppName} + + ${project.build.directory}/azure-functions/${functionAppName} - ${project.basedir}/src/main/azure + ${project.basedir}/src/main/azure + ** diff --git a/spring-cloud-function-samples/function-sample-azure/src/main/azure/local.settings.json b/spring-cloud-function-samples/function-sample-azure/src/main/azure/local.settings.json index df147e2c2..3470fde9a 100644 --- a/spring-cloud-function-samples/function-sample-azure/src/main/azure/local.settings.json +++ b/spring-cloud-function-samples/function-sample-azure/src/main/azure/local.settings.json @@ -1,8 +1,8 @@ { - "IsEncrypted": false, - "Values": { - "AzureWebJobsStorage": "", - "AzureWebJobsDashboard": "", - "FUNCTIONS_WORKER_RUNTIME": "java" - } + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "", + "AzureWebJobsDashboard": "", + "FUNCTIONS_WORKER_RUNTIME": "java" + } } diff --git a/spring-cloud-function-samples/function-sample-azure/src/main/java/example/Config.java b/spring-cloud-function-samples/function-sample-azure/src/main/java/example/Config.java index 7cec312bb..b83054fd6 100644 --- a/spring-cloud-function-samples/function-sample-azure/src/main/java/example/Config.java +++ b/spring-cloud-function-samples/function-sample-azure/src/main/java/example/Config.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -22,6 +22,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; +// @checkstyle:off @SpringBootApplication public class Config { @@ -33,7 +34,9 @@ public class Config { public Function uppercase() { return foo -> new Bar(foo.getValue().toUpperCase()); } + } +// @checkstyle:on class Foo { @@ -42,25 +45,26 @@ class Foo { Foo() { } - public String lowercase() { - return value.toLowerCase(); - } - - public Foo(String value) { + Foo(String value) { this.value = value; } + public String lowercase() { + return this.value.toLowerCase(); + } + public String uppercase() { - return value.toUpperCase(); + return this.value.toUpperCase(); } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } class Bar { @@ -70,16 +74,16 @@ class Bar { Bar() { } - public Bar(String value) { + Bar(String value) { this.value = value; } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java b/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java index 00a076372..51b7b9190 100644 --- a/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java +++ b/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java @@ -1,11 +1,11 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -28,6 +28,7 @@ import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHa * @author Soby Chacko */ public class FooHandler extends AzureSpringBootRequestHandler { + @FunctionName("uppercase") public Bar execute( @HttpTrigger(name = "req", methods = { HttpMethod.GET, diff --git a/spring-cloud-function-samples/function-sample-azure/src/test/java/example/MapTests.java b/spring-cloud-function-samples/function-sample-azure/src/test/java/example/MapTests.java index e7ca20393..be695a55c 100644 --- a/spring-cloud-function-samples/function-sample-azure/src/test/java/example/MapTests.java +++ b/spring-cloud-function-samples/function-sample-azure/src/test/java/example/MapTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-samples/function-sample-compiler/build.gradle b/spring-cloud-function-samples/function-sample-compiler/build.gradle index 13afb8e0f..ee3becec8 100644 --- a/spring-cloud-function-samples/function-sample-compiler/build.gradle +++ b/spring-cloud-function-samples/function-sample-compiler/build.gradle @@ -39,9 +39,9 @@ ext { ext['reactor.version'] = "3.1.7.RELEASE" dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" - } + imports { + mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" + } } dependencies { diff --git a/spring-cloud-function-samples/function-sample-compiler/pom.xml b/spring-cloud-function-samples/function-sample-compiler/pom.xml index 1657f1af2..6ebb248f3 100644 --- a/spring-cloud-function-samples/function-sample-compiler/pom.xml +++ b/spring-cloud-function-samples/function-sample-compiler/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 io.spring.sample @@ -19,7 +20,8 @@ 1.8 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + 3.1.2.RELEASE 1.0.17.RELEASE diff --git a/spring-cloud-function-samples/function-sample-compiler/src/main/java/com/example/SampleApplication.java b/spring-cloud-function-samples/function-sample-compiler/src/main/java/com/example/SampleApplication.java index ce9fe95ff..1889e7715 100644 --- a/spring-cloud-function-samples/function-sample-compiler/src/main/java/com/example/SampleApplication.java +++ b/spring-cloud-function-samples/function-sample-compiler/src/main/java/com/example/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,10 +19,13 @@ package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +// @checkstyle:off @SpringBootApplication public class SampleApplication { public static void main(String[] args) throws Exception { SpringApplication.run(SampleApplication.class, args); } + } +// @checkstyle:on diff --git a/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledConsumerTests.java b/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledConsumerTests.java index aafbb9004..2a902282e 100644 --- a/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledConsumerTests.java +++ b/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledConsumerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -44,7 +44,7 @@ public class SampleCompiledConsumerTests { @Test public void print() { assertThat(new TestRestTemplate().postForObject( - "http://localhost:" + port + "/test", "it works", String.class)).isNull(); + "http://localhost:" + this.port + "/test", "it works", String.class)).isNull(); assertEquals("it works", Reference.instance); } @@ -55,5 +55,7 @@ public class SampleCompiledConsumerTests { public static void set(Object o) { instance = o; } + } + } diff --git a/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledFunctionTests.java b/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledFunctionTests.java index 06b48178d..c2a898c4b 100644 --- a/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledFunctionTests.java +++ b/spring-cloud-function-samples/function-sample-compiler/src/test/java/com/example/SampleCompiledFunctionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -43,7 +43,7 @@ public class SampleCompiledFunctionTests { @Test public void lowercase() { assertThat(new TestRestTemplate().postForObject( - "http://localhost:" + port + "/test", "it works", String.class)) + "http://localhost:" + this.port + "/test", "it works", String.class)) .contains("it works!!!"); } diff --git a/spring-cloud-function-samples/function-sample-pof/build.gradle b/spring-cloud-function-samples/function-sample-pof/build.gradle index 13afb8e0f..ee3becec8 100644 --- a/spring-cloud-function-samples/function-sample-pof/build.gradle +++ b/spring-cloud-function-samples/function-sample-pof/build.gradle @@ -39,9 +39,9 @@ ext { ext['reactor.version'] = "3.1.7.RELEASE" dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" - } + imports { + mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" + } } dependencies { diff --git a/spring-cloud-function-samples/function-sample-pof/pom.xml b/spring-cloud-function-samples/function-sample-pof/pom.xml index 21c045b92..310a7ab02 100644 --- a/spring-cloud-function-samples/function-sample-pof/pom.xml +++ b/spring-cloud-function-samples/function-sample-pof/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 io.spring.sample @@ -13,7 +14,7 @@ org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE - + @@ -21,7 +22,8 @@ UTF-8 1.8 3.1.2.RELEASE - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + diff --git a/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Application.java b/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Application.java index 0122adaa4..04db3fd0a 100644 --- a/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Application.java +++ b/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Application.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,10 +19,13 @@ package functions; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +// @checkstyle:off @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } + } +// @checkstyle:on diff --git a/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Greeter.java b/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Greeter.java index 0ae801c82..c1ece9d6f 100644 --- a/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Greeter.java +++ b/spring-cloud-function-samples/function-sample-pof/src/main/java/functions/Greeter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -18,9 +18,12 @@ package functions; import java.util.function.Function; +// @checkstyle:off public class Greeter implements Function { public String apply(String name) { return "Hello " + name; } + } +// @checkstyle:on diff --git a/spring-cloud-function-samples/function-sample-pojo/build.gradle b/spring-cloud-function-samples/function-sample-pojo/build.gradle index 00db5429b..47409b0e9 100644 --- a/spring-cloud-function-samples/function-sample-pojo/build.gradle +++ b/spring-cloud-function-samples/function-sample-pojo/build.gradle @@ -39,9 +39,9 @@ ext { ext['reactor.version'] = "3.1.7.RELEASE" dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" - } + imports { + mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" + } } dependencies { diff --git a/spring-cloud-function-samples/function-sample-pojo/pom.xml b/spring-cloud-function-samples/function-sample-pojo/pom.xml index 7b173af57..97e2c3444 100644 --- a/spring-cloud-function-samples/function-sample-pojo/pom.xml +++ b/spring-cloud-function-samples/function-sample-pojo/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 io.spring.sample @@ -14,12 +15,13 @@ org.springframework.boot spring-boot-starter-parent 2.1.2.RELEASE - + 1.8 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + 1.0.17.RELEASE diff --git a/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/LowercaseConfiguration.java b/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/LowercaseConfiguration.java index 84b128767..d6f381a53 100644 --- a/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/LowercaseConfiguration.java +++ b/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/LowercaseConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -18,11 +18,11 @@ package com.example; import java.util.function.Function; +import reactor.core.publisher.Flux; + import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * diff --git a/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/SampleApplication.java b/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/SampleApplication.java index bd836f9a0..a0cebd78d 100644 --- a/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/SampleApplication.java +++ b/spring-cloud-function-samples/function-sample-pojo/src/main/java/com/example/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2016 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package com.example; import java.util.HashMap; @@ -20,25 +21,26 @@ import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; +import reactor.core.publisher.Flux; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.util.MultiValueMap; -import reactor.core.publisher.Flux; - +// @checkstyle:off @SpringBootApplication public class SampleApplication { + public static void main(String[] args) { + SpringApplication.run(SampleApplication.class, args); + } + @Bean public Function uppercase() { return value -> new Bar(value.uppercase()); } - public static void main(String[] args) { - SpringApplication.run(SampleApplication.class, args); - } - @Bean public Function, Map> sum() { return multiValueMap -> { @@ -55,6 +57,7 @@ public class SampleApplication { } } +// @checkstyle:on class Foo { @@ -63,25 +66,26 @@ class Foo { Foo() { } - public String lowercase() { - return value.toLowerCase(); - } - - public Foo(String value) { + Foo(String value) { this.value = value; } + public String lowercase() { + return this.value.toLowerCase(); + } + public String uppercase() { - return value.toUpperCase(); + return this.value.toUpperCase(); } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } class Bar { @@ -91,12 +95,12 @@ class Bar { Bar() { } - public Bar(String value) { + Bar(String value) { this.value = value; } public String getValue() { - return value; + return this.value; } public void setValue(String value) { diff --git a/spring-cloud-function-samples/function-sample-pojo/src/main/resources/application.properties b/spring-cloud-function-samples/function-sample-pojo/src/main/resources/application.properties index 4b88c4acf..b5dc321cf 100644 --- a/spring-cloud-function-samples/function-sample-pojo/src/main/resources/application.properties +++ b/spring-cloud-function-samples/function-sample-pojo/src/main/resources/application.properties @@ -1,4 +1,4 @@ -spring.cloud.stream.bindings.input.destination: foos -spring.cloud.stream.bindings.output.destination: bars -spring.cloud.function.stream.processor.name: uppercase -management.security.enabled: false \ No newline at end of file +spring.cloud.stream.bindings.input.destination:foos +spring.cloud.stream.bindings.output.destination:bars +spring.cloud.function.stream.processor.name:uppercase +management.security.enabled:false diff --git a/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationMvcTests.java b/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationMvcTests.java index 7c32a9e2a..ebc863205 100644 --- a/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationMvcTests.java +++ b/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationMvcTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -15,12 +15,11 @@ */ package com.example; -import static org.assertj.core.api.Assertions.assertThat; - import java.net.URI; import org.junit.Test; import org.junit.runner.RunWith; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; @@ -30,6 +29,8 @@ import org.springframework.http.RequestEntity; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; +import static org.assertj.core.api.Assertions.assertThat; + /** * @author Dave Syer */ @@ -38,13 +39,14 @@ import org.springframework.test.context.junit4.SpringRunner; public class SampleApplicationMvcTests { @Autowired - private TestRestTemplate rest; + private TestRestTemplate rest; @Test public void words() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity.get(new URI("/words")) - .accept(MediaType.APPLICATION_JSON).build(), String.class); - assertThat(result.getBody()).isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"); + ResponseEntity result = this.rest.exchange(RequestEntity.get(new URI("/words")) + .accept(MediaType.APPLICATION_JSON).build(), String.class); + assertThat(result.getBody()) + .isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"); } } diff --git a/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java b/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java index 6f7b7be29..557629178 100644 --- a/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java +++ b/spring-cloud-function-samples/function-sample-pojo/src/test/java/com/example/SampleApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -19,7 +19,6 @@ import java.net.URI; import java.util.Arrays; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; @@ -48,43 +47,45 @@ public class SampleApplicationTests { @LocalServerPort private int port; + private TestRestTemplate rest = new TestRestTemplate(); @Before public void before() { - headers = new HttpHeaders(); - headers.setContentType(MediaType.APPLICATION_JSON); + this.headers = new HttpHeaders(); + this.headers.setContentType(MediaType.APPLICATION_JSON); } @Test public void words() { - assertThat(rest.getForObject("http://localhost:" + port + "/words", String.class)) + assertThat(this.rest.getForObject("http://localhost:" + this.port + "/words", String.class)) .isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"); } @Test public void uppercase() { - assertThat(rest.postForObject("http://localhost:" + port + "/uppercase", - new HttpEntity<>("[{\"value\":\"foo\"}]", headers), String.class)) + assertThat(this.rest.postForObject("http://localhost:" + this.port + "/uppercase", + new HttpEntity<>("[{\"value\":\"foo\"}]", this.headers), String.class)) .isEqualTo("[{\"value\":\"FOO\"}]"); } @Test public void composite() { - assertThat(rest.getForObject("http://localhost:" + port + "/words,uppercase", + assertThat(this.rest.getForObject("http://localhost:" + this.port + "/words,uppercase", String.class)).isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]"); } @Test public void single() { - assertThat(rest.postForObject("http://localhost:" + port + "/uppercase", - new HttpEntity<>("{\"value\":\"foo\"}", headers), String.class)).isEqualTo("{\"value\":\"FOO\"}"); + assertThat(this.rest.postForObject("http://localhost:" + this.port + "/uppercase", + new HttpEntity<>("{\"value\":\"foo\"}", this.headers), String.class)) + .isEqualTo("{\"value\":\"FOO\"}"); } @Test public void lowercase() { - assertThat(rest.postForObject("http://localhost:" + port + "/lowercase", - new HttpEntity<>("[{\"value\":\"Foo\"}]", headers), String.class)) + assertThat(this.rest.postForObject("http://localhost:" + this.port + "/lowercase", + new HttpEntity<>("[{\"value\":\"Foo\"}]", this.headers), String.class)) .isEqualTo("[{\"value\":\"foo\"}]"); } @@ -96,8 +97,8 @@ public class SampleApplicationTests { map.put("A", Arrays.asList("1", "2", "3")); map.put("B", Arrays.asList("5", "6")); - assertThat(rest.exchange( - RequestEntity.post(new URI("http://localhost:" + port + "/sum")) + assertThat(this.rest.exchange( + RequestEntity.post(new URI("http://localhost:" + this.port + "/sum")) .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_FORM_URLENCODED).body(map), String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]"); @@ -112,9 +113,11 @@ public class SampleApplicationTests { map.put("A", Arrays.asList("1", "2", "3")); map.put("B", Arrays.asList("5", "6")); - assertThat(rest.exchange( - RequestEntity.post(new URI("http://localhost:" + port + "/sum")).accept(MediaType.APPLICATION_JSON) + assertThat(this.rest.exchange( + RequestEntity.post(new URI("http://localhost:" + this.port + "/sum")) + .accept(MediaType.APPLICATION_JSON) .contentType(MediaType.MULTIPART_FORM_DATA).body(map), String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]"); } + } diff --git a/spring-cloud-function-samples/function-sample-task/build.gradle b/spring-cloud-function-samples/function-sample-task/build.gradle index d2f571094..639b41f75 100644 --- a/spring-cloud-function-samples/function-sample-task/build.gradle +++ b/spring-cloud-function-samples/function-sample-task/build.gradle @@ -39,9 +39,9 @@ ext { ext['reactor.version'] = "3.1.7.RELEASE" dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" - } + imports { + mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" + } } dependencies { diff --git a/spring-cloud-function-samples/function-sample-task/pom.xml b/spring-cloud-function-samples/function-sample-task/pom.xml index aa18fe1d8..8c2928128 100644 --- a/spring-cloud-function-samples/function-sample-task/pom.xml +++ b/spring-cloud-function-samples/function-sample-task/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 io.spring.sample @@ -19,7 +20,8 @@ 1.8 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + 1.0.10.RELEASE 3.1.2.RELEASE diff --git a/spring-cloud-function-samples/function-sample-task/src/main/java/com/example/SampleApplication.java b/spring-cloud-function-samples/function-sample-task/src/main/java/com/example/SampleApplication.java index ce9fe95ff..1889e7715 100644 --- a/spring-cloud-function-samples/function-sample-task/src/main/java/com/example/SampleApplication.java +++ b/spring-cloud-function-samples/function-sample-task/src/main/java/com/example/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -19,10 +19,13 @@ package com.example; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +// @checkstyle:off @SpringBootApplication public class SampleApplication { public static void main(String[] args) throws Exception { SpringApplication.run(SampleApplication.class, args); } + } +// @checkstyle:on diff --git a/spring-cloud-function-samples/function-sample-task/src/main/resources/application.yml b/spring-cloud-function-samples/function-sample-task/src/main/resources/application.yml index 09ff71a48..ede29b1f0 100644 --- a/spring-cloud-function-samples/function-sample-task/src/main/resources/application.yml +++ b/spring-cloud-function-samples/function-sample-task/src/main/resources/application.yml @@ -4,7 +4,7 @@ spring: task: supplier: words function: uppercase - consumer: print + consumer: print compile: words: type: supplier diff --git a/spring-cloud-function-samples/function-sample/build.gradle b/spring-cloud-function-samples/function-sample/build.gradle index 0fc721dbe..76eb4efff 100644 --- a/spring-cloud-function-samples/function-sample/build.gradle +++ b/spring-cloud-function-samples/function-sample/build.gradle @@ -38,9 +38,9 @@ ext { } dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" - } + imports { + mavenBom "org.springframework.cloud:spring-cloud-function-dependencies:${springCloudFunctionVersion}" + } } dependencies { diff --git a/spring-cloud-function-samples/function-sample/pom.xml b/spring-cloud-function-samples/function-sample/pom.xml index 3035cc5a2..558782e00 100644 --- a/spring-cloud-function-samples/function-sample/pom.xml +++ b/spring-cloud-function-samples/function-sample/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 io.spring.sample @@ -19,7 +20,8 @@ 1.8 - 2.0.2.BUILD-SNAPSHOT + 2.0.2.BUILD-SNAPSHOT + 1.0.17.RELEASE diff --git a/spring-cloud-function-samples/function-sample/src/main/java/com/example/SampleApplication.java b/spring-cloud-function-samples/function-sample/src/main/java/com/example/SampleApplication.java index 679dfcc53..28876cbc2 100644 --- a/spring-cloud-function-samples/function-sample/src/main/java/com/example/SampleApplication.java +++ b/spring-cloud-function-samples/function-sample/src/main/java/com/example/SampleApplication.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -19,6 +19,8 @@ package com.example; import java.util.function.Function; import java.util.function.Supplier; +import reactor.core.publisher.Flux; + import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.function.compiler.FunctionCompiler; @@ -26,11 +28,14 @@ import org.springframework.cloud.function.compiler.proxy.LambdaCompilingFunction import org.springframework.context.annotation.Bean; import org.springframework.core.io.ByteArrayResource; -import reactor.core.publisher.Flux; - +// @checkstyle:off @SpringBootApplication public class SampleApplication { + public static void main(String[] args) throws Exception { + SpringApplication.run(SampleApplication.class, args); + } + @Bean public Function uppercase() { return value -> value.toUpperCase(); @@ -52,17 +57,21 @@ public class SampleApplication { } @Bean - public Function compiledUppercase(FunctionCompiler compiler) { + public Function compiledUppercase( + FunctionCompiler compiler) { String lambda = "s -> s.toUpperCase()"; - LambdaCompilingFunction function = new LambdaCompilingFunction<>(new ByteArrayResource(lambda.getBytes()), compiler); + LambdaCompilingFunction function = new LambdaCompilingFunction<>( + new ByteArrayResource(lambda.getBytes()), compiler); function.setTypeParameterizations("String", "String"); return function; } @Bean - public Function, Flux> compiledLowercase(FunctionCompiler, Flux> compiler) { + public Function, Flux> compiledLowercase( + FunctionCompiler, Flux> compiler) { String lambda = "f->f.map(o->o.toString().toLowerCase())"; - return new LambdaCompilingFunction<>(new ByteArrayResource(lambda.getBytes()), compiler); + return new LambdaCompilingFunction<>(new ByteArrayResource(lambda.getBytes()), + compiler); } @Bean @@ -70,7 +79,5 @@ public class SampleApplication { return new FunctionCompiler<>(); } - public static void main(String[] args) throws Exception { - SpringApplication.run(SampleApplication.class, args); - } } +// @checkstyle:on diff --git a/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/CharCounter.java b/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/CharCounter.java index a6ebb1422..93e99540c 100644 --- a/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/CharCounter.java +++ b/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/CharCounter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -27,4 +27,5 @@ public class CharCounter implements Function { public Integer apply(String word) { return word.length(); } + } diff --git a/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Exclaimer.java b/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Exclaimer.java index 6de425a1c..0dc2bdd1f 100644 --- a/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Exclaimer.java +++ b/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Exclaimer.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -27,6 +27,7 @@ public class Exclaimer implements Function, Flux> { @Override public Flux apply(Flux words) { - return words.map(word->word+"!!!"); + return words.map(word -> word + "!!!"); } + } diff --git a/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Greeter.java b/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Greeter.java index e4f2bcae0..1c40d1a02 100644 --- a/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Greeter.java +++ b/spring-cloud-function-samples/function-sample/src/main/java/com/example/functions/Greeter.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -27,4 +27,5 @@ public class Greeter implements Function { public String apply(String name) { return "Hello " + name; } + } diff --git a/spring-cloud-function-samples/function-sample/src/main/resources/META-INF/thin-rabbit.properties b/spring-cloud-function-samples/function-sample/src/main/resources/META-INF/thin-rabbit.properties index 1c05bd28f..6906ff808 100644 --- a/spring-cloud-function-samples/function-sample/src/main/resources/META-INF/thin-rabbit.properties +++ b/spring-cloud-function-samples/function-sample/src/main/resources/META-INF/thin-rabbit.properties @@ -1,5 +1,5 @@ -boms.spring-cloud-dependencies: org.springframework.cloud:spring-cloud-dependencies:Edgware.SR3 -dependencies.spring-cloud-function-stream: org.springframework.cloud:spring-cloud-function-stream -dependencies.spring-cloud-stream-rabbit: org.springframework.cloud:spring-cloud-starter-stream-rabbit -exclusions.spring-cloud-function-web: org.springframework.cloud:spring-cloud-starter-function-web -exclusions.http-client: com.rabbitmq:http-client +boms.spring-cloud-dependencies:org.springframework.cloud:spring-cloud-dependencies:Edgware.SR3 +dependencies.spring-cloud-function-stream:org.springframework.cloud:spring-cloud-function-stream +dependencies.spring-cloud-stream-rabbit:org.springframework.cloud:spring-cloud-starter-stream-rabbit +exclusions.spring-cloud-function-web:org.springframework.cloud:spring-cloud-starter-function-web +exclusions.http-client:com.rabbitmq:http-client diff --git a/spring-cloud-function-samples/function-sample/src/main/resources/application.properties b/spring-cloud-function-samples/function-sample/src/main/resources/application.properties index e8f295050..c1a56fa72 100644 --- a/spring-cloud-function-samples/function-sample/src/main/resources/application.properties +++ b/spring-cloud-function-samples/function-sample/src/main/resources/application.properties @@ -1,2 +1,2 @@ -spring.cloud.function.stream.processor.name: uppercase -spring.cloud.function.scan.packages: com.example.functions +spring.cloud.function.stream.processor.name:uppercase +spring.cloud.function.scan.packages:com.example.functions diff --git a/spring-cloud-function-samples/function-sample/src/test/java/com/example/FunctionTests.java b/spring-cloud-function-samples/function-sample/src/test/java/com/example/FunctionTests.java index 2f599144d..623d6f8e0 100644 --- a/spring-cloud-function-samples/function-sample/src/test/java/com/example/FunctionTests.java +++ b/spring-cloud-function-samples/function-sample/src/test/java/com/example/FunctionTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 the original author or authors. + * Copyright 2012-2019 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. @@ -16,31 +16,29 @@ package com.example; -import static org.junit.Assert.assertEquals; - import java.util.List; -import org.junit.Test; - import com.example.functions.CharCounter; import com.example.functions.Exclaimer; import com.example.functions.Greeter; - +import org.junit.Test; import reactor.core.publisher.Flux; +import static org.junit.Assert.assertEquals; + public class FunctionTests { private final SampleApplication functions = new SampleApplication(); @Test public void testUppercase() { - String output = functions.uppercase().apply("foobar"); + String output = this.functions.uppercase().apply("foobar"); assertEquals("FOOBAR", output); } @Test public void testLowercase() { - Flux output = functions.lowercase().apply(Flux.just("FOO", "BAR")); + Flux output = this.functions.lowercase().apply(Flux.just("FOO", "BAR")); List results = output.collectList().block(); assertEquals(2, results.size()); assertEquals("foo", results.get(0)); @@ -49,13 +47,13 @@ public class FunctionTests { @Test public void testHello() { - String output = functions.hello().get(); - assertEquals("hello", output); + String output = this.functions.hello().get(); + assertEquals("hello", output); } @Test public void testWords() { - Flux output = functions.words().get(); + Flux output = this.functions.words().get(); List results = output.collectList().block(); assertEquals(2, results.size()); assertEquals("foo", results.get(0)); @@ -81,4 +79,5 @@ public class FunctionTests { public void testCharCounter() { assertEquals((Integer) 21, new CharCounter().apply("this is 21 chars long")); } + } diff --git a/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationMvcTests.java b/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationMvcTests.java index 38d9309c5..3c8a623ce 100644 --- a/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationMvcTests.java +++ b/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationMvcTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -40,7 +40,7 @@ public class SampleApplicationMvcTests { @Test @Ignore("FIXME") public void words() throws Exception { - mockMvc.perform(get("/words")).andExpect(content().string("[\"foo\",\"bar\"]")); + this.mockMvc.perform(get("/words")).andExpect(content().string("[\"foo\",\"bar\"]")); } } diff --git a/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationTests.java b/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationTests.java index 56a2e7ba3..a3565f8bd 100644 --- a/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationTests.java +++ b/spring-cloud-function-samples/function-sample/src/test/java/com/example/SampleApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -16,61 +16,69 @@ package com.example; -import static org.junit.Assert.assertEquals; - import java.util.List; import java.util.function.Function; import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; -import reactor.core.publisher.Flux; +import static org.junit.Assert.assertEquals; @RunWith(SpringRunner.class) @SpringBootTest public class SampleApplicationTests { + @Autowired + private Function uppercase; + @Autowired + private Function, Flux> lowercase; + @Autowired + private Supplier hello; + @Autowired + private Supplier> words; + @Autowired + private Function compiledUppercase; + @Autowired + private Function, Flux> compiledLowercase; + @Autowired + private Function greeter; + @Autowired + private Function, Flux> exclaimer; + @Autowired + private Function charCounter; + @Test public void contextLoads() { } - @Autowired - private Function uppercase; - @Test public void testUppercase() { String output = this.uppercase.apply("foobar"); assertEquals("FOOBAR", output); } - @Autowired - private Function, Flux> lowercase; - @Test public void testLowercase() { Flux output = this.lowercase.apply(Flux.just("FOO", "BAR")); List results = output.collectList().block(); assertEquals(2, results.size()); assertEquals("foo", results.get(0)); - assertEquals("bar", results.get(1)); + assertEquals("bar", results.get(1)); } - @Autowired - private Supplier hello; - @Test public void testHello() { String output = this.hello.get(); - assertEquals("hello", output); + assertEquals("hello", output); } - @Autowired - private Supplier> words; + // the following are contributed via @FunctionScan: @Test public void testWords() { @@ -78,21 +86,15 @@ public class SampleApplicationTests { List results = output.collectList().block(); assertEquals(2, results.size()); assertEquals("foo", results.get(0)); - assertEquals("bar", results.get(1)); + assertEquals("bar", results.get(1)); } - @Autowired - private Function compiledUppercase; - @Test public void testCompiledUppercase() { String output = this.compiledUppercase.apply("foobar"); assertEquals("FOOBAR", output); } - @Autowired - private Function, Flux> compiledLowercase; - @Test public void testCompiledLowercase() { Flux input = Flux.just("FOO", "BAR"); @@ -103,20 +105,12 @@ public class SampleApplicationTests { assertEquals("bar", results.get(1)); } - // the following are contributed via @FunctionScan: - - @Autowired - private Function greeter; - @Test public void testGreeter() { String greeting = this.greeter.apply("World"); assertEquals("Hello World", greeting); } - @Autowired - private Function, Flux> exclaimer; - @Test public void testExclaimer() { Flux input = Flux.just("foo", "bar"); @@ -127,12 +121,10 @@ public class SampleApplicationTests { assertEquals("bar!!!", results.get(1)); } - @Autowired - private Function charCounter; - @Test public void testCharCounter() { Integer length = this.charCounter.apply("the quick brown fox"); assertEquals(new Integer(19), length); } -} \ No newline at end of file + +} diff --git a/spring-cloud-function-samples/pom.xml b/spring-cloud-function-samples/pom.xml index 14e3b98b7..4bda5e244 100644 --- a/spring-cloud-function-samples/pom.xml +++ b/spring-cloud-function-samples/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 spring-cloud-function-samples diff --git a/spring-cloud-function-task/pom.xml b/spring-cloud-function-task/pom.xml index edd7eafc3..36106f9e2 100644 --- a/spring-cloud-function-task/pom.xml +++ b/spring-cloud-function-task/pom.xml @@ -1,5 +1,7 @@ - + 4.0.0 spring-cloud-function-task diff --git a/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskApplication.java b/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskApplication.java index 9218ec86c..f9df1cc31 100644 --- a/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskApplication.java +++ b/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskApplication.java @@ -1,12 +1,12 @@ /* - * Copyright 2016 the original author or authors. - * + * Copyright 2012-2019 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. @@ -22,10 +22,13 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; /** * @author Mark Fisher */ +// @checkstyle:off @SpringBootApplication public class TaskApplication { public static void main(String[] args) { SpringApplication.run(TaskApplication.class, args); } + } +// @checkstyle:on diff --git a/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfiguration.java b/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfiguration.java index 9dfa95a99..49f2ff528 100644 --- a/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfiguration.java +++ b/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfiguration.java @@ -1,12 +1,12 @@ /* - * Copyright 2016-2017 the original author or authors. - * + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; @@ -31,8 +32,6 @@ import org.springframework.cloud.task.configuration.EnableTask; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import reactor.core.publisher.Mono; - /** * @author Mark Fisher */ @@ -48,9 +47,9 @@ public class TaskConfiguration { @Bean public CommandLineRunner commandLineRunner(FunctionCatalog registry) { final Supplier> supplier = registry.lookup(Supplier.class, - properties.getSupplier()); + this.properties.getSupplier()); final Function, Publisher> function = registry - .lookup(Function.class, properties.getFunction()); + .lookup(Function.class, this.properties.getFunction()); final Consumer> consumer = consumer(registry); CommandLineRunner runner = new CommandLineRunner() { @@ -64,12 +63,13 @@ public class TaskConfiguration { private Consumer> consumer(FunctionCatalog registry) { Consumer> consumer = registry.lookup(Consumer.class, - properties.getConsumer()); + this.properties.getConsumer()); if (consumer != null) { return consumer; } - Function, Publisher> function = registry.lookup(Function.class, - properties.getConsumer()); + Function, Publisher> function = registry + .lookup(Function.class, this.properties.getConsumer()); return flux -> Mono.from(function.apply(flux)).subscribe(); } + } diff --git a/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfigurationProperties.java b/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfigurationProperties.java index 228dee402..15d31ff61 100644 --- a/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfigurationProperties.java +++ b/spring-cloud-function-task/src/main/java/org/springframework/cloud/function/task/TaskConfigurationProperties.java @@ -1,11 +1,11 @@ /* - * Copyright 2016 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -31,7 +31,7 @@ public class TaskConfigurationProperties { private String consumer; public String getSupplier() { - return supplier; + return this.supplier; } public void setSupplier(String supplier) { @@ -39,7 +39,7 @@ public class TaskConfigurationProperties { } public String getFunction() { - return function; + return this.function; } public void setFunction(String function) { @@ -47,10 +47,11 @@ public class TaskConfigurationProperties { } public String getConsumer() { - return consumer; + return this.consumer; } public void setConsumer(String consumer) { this.consumer = consumer; } + } diff --git a/spring-cloud-function-web/pom.xml b/spring-cloud-function-web/pom.xml index 178d4ab93..3678bf5e0 100644 --- a/spring-cloud-function-web/pom.xml +++ b/spring-cloud-function-web/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 spring-cloud-function-web diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java index 23f5d4beb..9db6d2848 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/BasicStringConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -21,10 +21,17 @@ import org.springframework.cloud.function.context.catalog.FunctionInspector; import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.support.DefaultConversionService; +/** + * Simple implementation of a {@link StringConverter}. + * + * @author Dave Syer + */ public class BasicStringConverter implements StringConverter { private ConversionService conversionService; + private ConfigurableListableBeanFactory registry; + private FunctionInspector inspector; public BasicStringConverter(FunctionInspector inspector, @@ -35,16 +42,14 @@ public class BasicStringConverter implements StringConverter { @Override public Object convert(Object function, String value) { - if (conversionService == null && registry != null) { - ConversionService conversionService = this.registry - .getConversionService(); + if (this.conversionService == null && this.registry != null) { + ConversionService conversionService = this.registry.getConversionService(); this.conversionService = conversionService != null ? conversionService : new DefaultConversionService(); } - Class type = inspector.getInputType(function); - return conversionService.canConvert(String.class, type) - ? conversionService.convert(value, type) - : value; + Class type = this.inspector.getInputType(function); + return this.conversionService.canConvert(String.class, type) + ? this.conversionService.convert(value, type) : value; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java index 22db3308e..82e9ca647 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RequestProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 the original author or authors. + * Copyright 2012-2019 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. @@ -34,6 +34,8 @@ import java.util.stream.Stream; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.ObjectProvider; import org.springframework.cloud.function.context.catalog.FunctionInspector; @@ -65,9 +67,6 @@ import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebInputException; import org.springframework.web.server.UnsupportedMediaTypeStatusException; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @author Oleg Zhurakousky @@ -123,23 +122,27 @@ public class RequestProcessor { .flatMap(body -> response(wrapper, body, false)); } - public Mono> post(FunctionWrapper wrapper, String body, boolean stream) { + public Mono> post(FunctionWrapper wrapper, String body, + boolean stream) { Object function = wrapper.handler(); - Class inputType = inspector.getInputType(function); + Class inputType = this.inspector.getInputType(function); Type itemType = getItemType(function); Object input = body; if (StringUtils.hasText(body)) { if (this.shouldUseJsonConversion(body, wrapper.headers.getContentType())) { - Type jsonType = body.startsWith("[") && Collection.class.isAssignableFrom(inputType) || body.startsWith("{") ? inputType : Collection.class; + Type jsonType = body.startsWith("[") + && Collection.class.isAssignableFrom(inputType) + || body.startsWith("{") ? inputType : Collection.class; if (body.startsWith("[")) { - jsonType = ResolvableType.forClassWithGenerics((Class)jsonType, (Class) itemType).getType(); + jsonType = ResolvableType.forClassWithGenerics((Class) jsonType, + (Class) itemType).getType(); } - input = mapper.toObject(body, jsonType); + input = this.mapper.toObject(body, jsonType); } else { - input = converter.convert(function, body); + input = this.converter.convert(function, body); } } @@ -148,7 +151,8 @@ public class RequestProcessor { private boolean shouldUseJsonConversion(String body, MediaType contentType) { return (body.startsWith("[") || body.startsWith("{")) - && (contentType == null || (contentType != null && !"text".equalsIgnoreCase(contentType.getType()))); + && (contentType == null || (contentType != null + && !"text".equalsIgnoreCase(contentType.getType()))); } public Mono> stream(FunctionWrapper request) { @@ -171,7 +175,7 @@ public class RequestProcessor { Flux flux; if (body != null) { if (Collection.class - .isAssignableFrom(inspector.getInputType(wrapper.handler()))) { + .isAssignableFrom(this.inspector.getInputType(wrapper.handler()))) { flux = Flux.just(body); } else { @@ -181,15 +185,18 @@ public class RequestProcessor { flux = Flux.fromIterable(iterable); } } - else if (MultiValueMap.class.isAssignableFrom(inspector.getInputType(wrapper.handler()))) { + else if (MultiValueMap.class + .isAssignableFrom(this.inspector.getInputType(wrapper.handler()))) { flux = Flux.just(wrapper.params()); } else { - throw new IllegalStateException("Failed to determine input for function call with parameters: '" + wrapper.params - + "' and headers: `" + wrapper.headers + "`"); + throw new IllegalStateException( + "Failed to determine input for function call with parameters: '" + + wrapper.params + "' and headers: `" + wrapper.headers + + "`"); } - if (inspector.isMessage(function)) { + if (this.inspector.isMessage(function)) { flux = messages(wrapper, function == null ? consumer : function, flux); } Mono> responseEntityMono = null; @@ -224,7 +231,7 @@ public class RequestProcessor { private Mono> stream(FunctionWrapper request, Publisher result) { BodyBuilder builder = ResponseEntity.ok(); - if (inspector.isMessage(request.handler())) { + if (this.inspector.isMessage(request.handler())) { result = Flux.from(result) .doOnNext(value -> addHeaders(builder, (Message) value)) .map(message -> MessageUtils.unpack(request.handler(), message) @@ -242,7 +249,7 @@ public class RequestProcessor { Publisher result, Boolean single, boolean getter) { BodyBuilder builder = ResponseEntity.ok(); - if (inspector.isMessage(handler)) { + if (this.inspector.isMessage(handler)) { result = Flux.from(result) .map(message -> MessageUtils.unpack(handler, message)) .doOnNext(value -> addHeaders(builder, value)) @@ -267,8 +274,8 @@ public class RequestProcessor { if (handler instanceof FluxWrapper) { handler = ((FluxWrapper) handler).getTarget(); } - Class type = inspector.getInputType(handler); - Class wrapper = inspector.getInputWrapper(handler); + Class type = this.inspector.getInputType(handler); + Class wrapper = this.inspector.getInputWrapper(handler); return Collection.class.isAssignableFrom(type) || Flux.class.equals(wrapper); } @@ -276,8 +283,8 @@ public class RequestProcessor { if (handler instanceof FluxWrapper) { handler = ((FluxWrapper) handler).getTarget(); } - Class type = inspector.getOutputType(handler); - Class wrapper = inspector.getOutputWrapper(handler); + Class type = this.inspector.getOutputType(handler); + Class wrapper = this.inspector.getOutputWrapper(handler); if (Stream.class.isAssignableFrom(type)) { return false; } @@ -294,8 +301,7 @@ public class RequestProcessor { ResolvableType actualType = elementType; Class resolvedType = elementType.resolve(); ReactiveAdapter adapter = (resolvedType != null - ? getAdapterRegistry().getAdapter(resolvedType) - : null); + ? getAdapterRegistry().getAdapter(resolvedType) : null); ServerHttpRequest request = exchange.getRequest(); ServerHttpResponse response = exchange.getResponse(); @@ -360,10 +366,8 @@ public class RequestProcessor { } private Throwable handleReadError(MethodParameter parameter, Throwable ex) { - return (ex instanceof DecodingException - ? new ServerWebInputException("Failed to read HTTP message", parameter, - ex) - : ex); + return (ex instanceof DecodingException ? new ServerWebInputException( + "Failed to read HTTP message", parameter, ex) : ex); } private ServerWebInputException handleMissingBody(MethodParameter param) { @@ -377,13 +381,14 @@ public class RequestProcessor { private Publisher value(Function, Publisher> function, Publisher value) { - Flux input = Flux.from(value).map(body -> converter.convert(function, body)); + Flux input = Flux.from(value) + .map(body -> this.converter.convert(function, body)); return Mono.from(function.apply(input)); } private Object getTargetFunction(Object function) { // we need to get the actual un-fluxed function so we can interrogate for types - Object target = inspector.getRegistration(function).getTarget(); + Object target = this.inspector.getRegistration(function).getTarget(); if (target instanceof FluxWrapper) { target = ((FluxWrapper) target).getTarget(); } @@ -391,12 +396,12 @@ public class RequestProcessor { } private Type getItemType(Object function) { - Class inputType = inspector.getInputType(function); + Class inputType = this.inspector.getInputType(function); if (!Collection.class.isAssignableFrom(inputType)) { return inputType; } - Type type = inspector.getRegistration(this.getTargetFunction(function)).getType() - .getType(); + Type type = this.inspector.getRegistration(this.getTargetFunction(function)) + .getType().getType(); if (type instanceof ParameterizedType) { type = ((ParameterizedType) type).getActualTypeArguments()[0]; } @@ -417,6 +422,9 @@ public class RequestProcessor { return type; } + /** + * Wrapper for functions. + */ public static class FunctionWrapper { private final Function, Publisher> function; @@ -442,7 +450,8 @@ public class RequestProcessor { } public Object handler() { - return function != null ? function : consumer != null ? consumer : supplier; + return this.function != null ? this.function + : this.consumer != null ? this.consumer : this.supplier; } public Function, Publisher> function() { @@ -458,7 +467,7 @@ public class RequestProcessor { } public MultiValueMap params() { - return params; + return this.params; } public HttpHeaders headers() { @@ -488,5 +497,7 @@ public class RequestProcessor { public Publisher argument() { return this.argument; } + } + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RestApplication.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RestApplication.java index c1e25cdb9..f64d51b28 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RestApplication.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/RestApplication.java @@ -1,11 +1,11 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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 + * 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, @@ -23,6 +23,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; /** * @author Mark Fisher */ +// @checkstyle:off @SpringBootConfiguration @EnableAutoConfiguration public class RestApplication { @@ -30,5 +31,6 @@ public class RestApplication { public static void main(String[] args) { SpringApplication.run(RestApplication.class, args); } -} +} +// @checkstyle:on diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/StringConverter.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/StringConverter.java index 092353c3a..dbfe3d418 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/StringConverter.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/StringConverter.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.web; /** diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/constants/WebRequestConstants.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/constants/WebRequestConstants.java index ed111dfb5..1fa970033 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/constants/WebRequestConstants.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/constants/WebRequestConstants.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,15 +23,33 @@ package org.springframework.cloud.function.web.constants; */ public abstract class WebRequestConstants { + /** + * Function attribute name. + */ public static final String FUNCTION = WebRequestConstants.class.getName() + ".function"; + + /** + * Consumer attribute name. + */ public static final String CONSUMER = WebRequestConstants.class.getName() + ".consumer"; + + /** + * Supplier attribute name. + */ public static final String SUPPLIER = WebRequestConstants.class.getName() + ".supplier"; + + /** + * Argument attribute name. + */ public static final String ARGUMENT = WebRequestConstants.class.getName() + ".argument"; - public static final String HANDLER = WebRequestConstants.class.getName() - + ".handler"; + + /** + * Handler attribute name. + */ + public static final String HANDLER = WebRequestConstants.class.getName() + ".handler"; } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionController.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionController.java index fa8b99599..429b22358 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionController.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionController.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; import org.springframework.cloud.function.web.RequestProcessor; import org.springframework.cloud.function.web.RequestProcessor.FunctionWrapper; @@ -38,8 +39,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @author Mark Fisher @@ -58,7 +57,7 @@ public class FunctionController { public Mono> form(ServerWebExchange request) { FunctionWrapper wrapper = wrapper(request); return request.getFormData().doOnSuccess(params -> wrapper.params(params)) - .then(Mono.defer(() -> processor.post(wrapper, null, false))); + .then(Mono.defer(() -> this.processor.post(wrapper, null, false))); } @PostMapping(path = "/**", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -67,7 +66,7 @@ public class FunctionController { FunctionWrapper wrapper = wrapper(request); return request.getMultipartData() .doOnSuccess(params -> wrapper.params(multi(params))) - .then(Mono.defer(() -> processor.post(wrapper, null, false))); + .then(Mono.defer(() -> this.processor.post(wrapper, null, false))); } private MultiValueMap multi(MultiValueMap body) { @@ -87,7 +86,7 @@ public class FunctionController { @ResponseBody public Mono> post(ServerWebExchange request) { FunctionWrapper wrapper = wrapper(request); - return processor.post(wrapper, request); + return this.processor.post(wrapper, request); } @PostMapping(path = "/**") @@ -95,7 +94,7 @@ public class FunctionController { public Mono> post(ServerWebExchange request, @RequestBody(required = false) String body) { FunctionWrapper wrapper = wrapper(request); - return processor.post(wrapper, body, false); + return this.processor.post(wrapper, body, false); } @PostMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @@ -103,21 +102,21 @@ public class FunctionController { public Mono> postStream(ServerWebExchange request, @RequestBody(required = false) String body) { FunctionWrapper wrapper = wrapper(request); - return processor.post(wrapper, body, true); + return this.processor.post(wrapper, body, true); } @GetMapping(path = "/**") @ResponseBody public Mono> get(ServerWebExchange request) { FunctionWrapper wrapper = wrapper(request); - return processor.get(wrapper); + return this.processor.get(wrapper); } @GetMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @ResponseBody public Mono> getStream(ServerWebExchange request) { FunctionWrapper wrapper = wrapper(request); - return processor.stream(wrapper); + return this.processor.stream(wrapper); } private FunctionWrapper wrapper(ServerWebExchange request) { @@ -139,4 +138,5 @@ public class FunctionController { } return wrapper; } + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionHandlerMapping.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionHandlerMapping.java index e251682ec..0fc08fa40 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionHandlerMapping.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/FunctionHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2017-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -35,8 +36,6 @@ import org.springframework.web.method.HandlerMethod; import org.springframework.web.reactive.result.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.server.ServerWebExchange; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @@ -57,7 +56,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping public FunctionHandlerMapping(FunctionCatalog catalog, FunctionController controller) { this.functions = catalog; - logger.info("FunctionCatalog: " + catalog); + this.logger.info("FunctionCatalog: " + catalog); setOrder(super.getOrder() - 5); this.controller = controller; } @@ -65,9 +64,9 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping @Override public void afterPropertiesSet() { super.afterPropertiesSet(); - detectHandlerMethods(controller); - while (prefix.endsWith("/")) { - prefix = prefix.substring(0, prefix.length() - 1); + detectHandlerMethods(this.controller); + while (this.prefix.endsWith("/")) { + this.prefix = this.prefix.substring(0, this.prefix.length() - 1); } } @@ -78,23 +77,23 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping @Override public Mono getHandlerInternal(ServerWebExchange request) { String path = request.getRequest().getPath().pathWithinApplication().value(); - if (StringUtils.hasText(prefix) && !path.startsWith(prefix)) { + if (StringUtils.hasText(this.prefix) && !path.startsWith(this.prefix)) { return Mono.empty(); } Mono handler = super.getHandlerInternal(request); if (path == null) { return handler; } - if (path.startsWith(prefix)) { - path = path.substring(prefix.length()); + if (path.startsWith(this.prefix)) { + path = path.substring(this.prefix.length()); } Object function = findFunctionForGet(request, path); if (function == null) { function = findFunctionForPost(request, path); } if (function != null) { - if (logger.isDebugEnabled()) { - logger.debug("Found function for POST: " + path); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Found function for POST: " + path); } request.getAttributes().put(WebRequestConstants.HANDLER, function); } @@ -107,12 +106,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping return null; } path = path.startsWith("/") ? path.substring(1) : path; - Consumer> consumer = functions.lookup(Consumer.class, path); + Consumer> consumer = this.functions.lookup(Consumer.class, path); if (consumer != null) { request.getAttributes().put(WebRequestConstants.CONSUMER, consumer); return consumer; } - Function function = functions.lookup(Function.class, path); + Function function = this.functions.lookup(Function.class, path); if (function != null) { request.getAttributes().put(WebRequestConstants.FUNCTION, function); return function; @@ -127,7 +126,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping path = path.startsWith("/") ? path.substring(1) : path; Object functionForGet = null; - Supplier> supplier = functions.lookup(Supplier.class, path); + Supplier> supplier = this.functions.lookup(Supplier.class, path); if (supplier != null) { request.getAttributes().put(WebRequestConstants.SUPPLIER, supplier); functionForGet = supplier; @@ -135,7 +134,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping else { StringBuilder builder = new StringBuilder(); String name = path; - String[] splitPath = path.split("/"); + String[] splitPath = path.split("/"); Function function = null; for (int i = 0; i < splitPath.length || function != null; i++) { String element = splitPath[i]; @@ -145,12 +144,11 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping builder.append(element); name = builder.toString(); - function = functions.lookup(Function.class, name); + function = this.functions.lookup(Function.class, name); if (function != null) { request.getAttributes().put(WebRequestConstants.FUNCTION, function); String value = path.length() > name.length() - ? path.substring(name.length() + 1) - : null; + ? path.substring(name.length() + 1) : null; request.getAttributes().put(WebRequestConstants.ARGUMENT, value); functionForGet = function; } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java index 5067c3e4e..24082cf1f 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/flux/ReactorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -16,6 +16,8 @@ package org.springframework.cloud.function.web.flux; +import reactor.core.publisher.Flux; + import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -34,8 +36,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @author Mark Fisher @@ -43,8 +43,8 @@ import reactor.core.publisher.Flux; */ @Configuration @ConditionalOnClass({ Flux.class, AsyncHandlerMethodReturnValueHandler.class }) -@ConditionalOnWebApplication(type=Type.REACTIVE) -@Import({FunctionController.class, RequestProcessor.class}) +@ConditionalOnWebApplication(type = Type.REACTIVE) +@Import({ FunctionController.class, RequestProcessor.class }) @AutoConfigureAfter({ JacksonAutoConfiguration.class, GsonAutoConfiguration.class }) public class ReactorAutoConfiguration { diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java index 2e08bdbb7..e18af6eb1 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/function/FunctionEndpointInitializer.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -23,6 +23,10 @@ import java.util.function.Function; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.netty.DisposableServer; +import reactor.netty.http.server.HttpServer; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.web.ErrorProperties; @@ -63,13 +67,7 @@ import static org.springframework.web.reactive.function.server.RequestPredicates import static org.springframework.web.reactive.function.server.RouterFunctions.route; import static org.springframework.web.reactive.function.server.ServerResponse.status; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.netty.DisposableServer; -import reactor.netty.http.server.HttpServer; - /** - * * @author Dave Syer * @since 2.0 * @@ -148,7 +146,7 @@ class FunctionEndpointInitializer private GenericApplicationContext context; - public ServerListener(GenericApplicationContext context) { + ServerListener(GenericApplicationContext context) { this.context = context; } @@ -212,7 +210,7 @@ class FunctionEndpointFactory { private RequestProcessor processor; - public FunctionEndpointFactory(FunctionCatalog catalog, FunctionInspector inspector, + FunctionEndpointFactory(FunctionCatalog catalog, FunctionInspector inspector, RequestProcessor processor, Environment environment) { String handler = environment.resolvePlaceholders("${function.handler}"); if (handler.startsWith("$")) { @@ -242,13 +240,13 @@ class FunctionEndpointFactory { public RouterFunction functionEndpoints() { return route(POST("/"), request -> { Class outputType = (Class) this.inspector.getOutputType(this.function); - FunctionWrapper wrapper = RequestProcessor.wrapper(function, null, null); + FunctionWrapper wrapper = RequestProcessor.wrapper(this.function, null, null); Mono> stream = request.bodyToMono(String.class) - .flatMap(content -> processor.post(wrapper, content, false)); + .flatMap(content -> this.processor.post(wrapper, content, false)); return stream.flatMap(entity -> status(entity.getStatusCode()) .headers(headers -> headers.addAll(entity.getHeaders())) .body(Mono.just((T) entity.getBody()), outputType)); }); } -} \ No newline at end of file +} diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionController.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionController.java index fb92aad86..5489a412a 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionController.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionController.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -23,6 +23,7 @@ import java.util.function.Function; import java.util.function.Supplier; import org.reactivestreams.Publisher; +import reactor.core.publisher.Mono; import org.springframework.cloud.function.web.RequestProcessor; import org.springframework.cloud.function.web.RequestProcessor.FunctionWrapper; @@ -36,8 +37,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.context.request.WebRequest; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @author Mark Fisher @@ -56,7 +55,7 @@ public class FunctionController { @ResponseBody public Mono> form(WebRequest request) { FunctionWrapper wrapper = wrapper(request); - return processor.post(wrapper, null, false); + return this.processor.post(wrapper, null, false); } @PostMapping(path = "/**") @@ -64,7 +63,7 @@ public class FunctionController { public Mono> post(WebRequest request, @RequestBody(required = false) String body) { FunctionWrapper wrapper = wrapper(request); - return processor.post(wrapper, body, false); + return this.processor.post(wrapper, body, false); } @PostMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @@ -72,22 +71,23 @@ public class FunctionController { public Mono>> postStream(WebRequest request, @RequestBody(required = false) String body) { FunctionWrapper wrapper = wrapper(request); - return processor.post(wrapper, body, true).map(response -> ResponseEntity.ok() - .headers(response.getHeaders()).body((Publisher) response.getBody())); + return this.processor.post(wrapper, body, true) + .map(response -> ResponseEntity.ok().headers(response.getHeaders()) + .body((Publisher) response.getBody())); } @GetMapping(path = "/**") @ResponseBody public Mono> get(WebRequest request) { FunctionWrapper wrapper = wrapper(request); - return processor.get(wrapper); + return this.processor.get(wrapper); } @GetMapping(path = "/**", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @ResponseBody public Mono>> getStream(WebRequest request) { FunctionWrapper wrapper = wrapper(request); - return processor.stream(wrapper).map(response -> ResponseEntity.ok() + return this.processor.stream(wrapper).map(response -> ResponseEntity.ok() .headers(response.getHeaders()).body((Publisher) response.getBody())); } @@ -116,4 +116,5 @@ public class FunctionController { } return wrapper; } + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionHandlerMapping.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionHandlerMapping.java index 4a98e4b9c..86da2154e 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionHandlerMapping.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/FunctionHandlerMapping.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -56,7 +56,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping public FunctionHandlerMapping(FunctionCatalog catalog, FunctionController controller) { this.functions = catalog; - logger.info("FunctionCatalog: " + catalog); + this.logger.info("FunctionCatalog: " + catalog); setOrder(super.getOrder() - 5); this.controller = controller; } @@ -64,9 +64,9 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping @Override public void afterPropertiesSet() { super.afterPropertiesSet(); - detectHandlerMethods(controller); - while (prefix.endsWith("/")) { - prefix = prefix.substring(0, prefix.length() - 1); + detectHandlerMethods(this.controller); + while (this.prefix.endsWith("/")) { + this.prefix = this.prefix.substring(0, this.prefix.length() - 1); } } @@ -86,24 +86,24 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping if (path == null) { return handler; } - if (StringUtils.hasText(prefix) && !path.startsWith(prefix)) { + if (StringUtils.hasText(this.prefix) && !path.startsWith(this.prefix)) { return null; } - if (path.startsWith(prefix)) { - path = path.substring(prefix.length()); + if (path.startsWith(this.prefix)) { + path = path.substring(this.prefix.length()); } Object function = findFunctionForGet(request, path); if (function != null) { - if (logger.isDebugEnabled()) { - logger.debug("Found function for GET: " + path); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Found function for GET: " + path); } request.setAttribute(WebRequestConstants.HANDLER, function); return handler; } function = findFunctionForPost(request, path); if (function != null) { - if (logger.isDebugEnabled()) { - logger.debug("Found function for POST: " + path); + if (this.logger.isDebugEnabled()) { + this.logger.debug("Found function for POST: " + path); } request.setAttribute(WebRequestConstants.HANDLER, function); return handler; @@ -116,12 +116,12 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping return null; } path = path.startsWith("/") ? path.substring(1) : path; - Consumer> consumer = functions.lookup(Consumer.class, path); + Consumer> consumer = this.functions.lookup(Consumer.class, path); if (consumer != null) { request.setAttribute(WebRequestConstants.CONSUMER, consumer); return consumer; } - Function function = functions.lookup(Function.class, path); + Function function = this.functions.lookup(Function.class, path); if (function != null) { request.setAttribute(WebRequestConstants.FUNCTION, function); return function; @@ -134,7 +134,7 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping return null; } path = path.startsWith("/") ? path.substring(1) : path; - Supplier> supplier = functions.lookup(Supplier.class, path); + Supplier> supplier = this.functions.lookup(Supplier.class, path); if (supplier != null) { request.setAttribute(WebRequestConstants.SUPPLIER, supplier); return supplier; @@ -150,7 +150,8 @@ public class FunctionHandlerMapping extends RequestMappingHandlerMapping name = builder.toString(); value = path.length() > name.length() ? path.substring(name.length() + 1) : null; - Function function = functions.lookup(Function.class, name); + Function function = this.functions.lookup(Function.class, + name); if (function != null) { request.setAttribute(WebRequestConstants.FUNCTION, function); request.setAttribute(WebRequestConstants.ARGUMENT, value); diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java index 4ae2fc375..04aa6dd93 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/mvc/ReactorAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -16,6 +16,8 @@ package org.springframework.cloud.function.web.mvc; +import reactor.core.publisher.Flux; + import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; @@ -34,15 +36,13 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.web.method.support.AsyncHandlerMethodReturnValueHandler; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @author Mark Fisher * @author Oleg Zhurakousky */ @Configuration -@ConditionalOnWebApplication(type=Type.SERVLET) +@ConditionalOnWebApplication(type = Type.SERVLET) @ConditionalOnClass({ Flux.class, AsyncHandlerMethodReturnValueHandler.class }) @Import({ FunctionController.class, RequestProcessor.class }) @AutoConfigureAfter({ JacksonAutoConfiguration.class, GsonAutoConfiguration.class }) @@ -60,4 +60,5 @@ public class ReactorAutoConfiguration { ConfigurableListableBeanFactory beanFactory) { return new BasicStringConverter(inspector, beanFactory); } + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/DestinationResolver.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/DestinationResolver.java index 1992f089a..d502cfe34 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/DestinationResolver.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/DestinationResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -25,4 +25,5 @@ import java.util.function.Supplier; public interface DestinationResolver { String destination(Supplier supplier, String name, Object value); + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/RequestBuilder.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/RequestBuilder.java index 61016bf08..2afdd31a4 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/RequestBuilder.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/RequestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -25,9 +25,9 @@ import org.springframework.http.HttpHeaders; * */ public interface RequestBuilder { - + URI uri(String destination); - + HttpHeaders headers(String destination, Object value); } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleDestinationResolver.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleDestinationResolver.java index 04d52bb7f..0359d2e38 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleDestinationResolver.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleDestinationResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleRequestBuilder.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleRequestBuilder.java index 5e244a3fb..b2e4962a5 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleRequestBuilder.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SimpleRequestBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -31,7 +31,9 @@ import org.springframework.http.HttpHeaders; class SimpleRequestBuilder implements RequestBuilder { private String baseUrl = "http://${destination}"; + private Map headers = new LinkedHashMap<>(); + private Environment environment; SimpleRequestBuilder(Environment environment) { @@ -42,10 +44,10 @@ class SimpleRequestBuilder implements RequestBuilder { public HttpHeaders headers(String destination, Object value) { // TODO: add message headers if any HttpHeaders result = new HttpHeaders(); - for (String key : headers.keySet()) { - String header = headers.get(key); + for (String key : this.headers.keySet()) { + String header = this.headers.get(key); header = header.replace("${destination}", destination); - header = environment.resolvePlaceholders(header); + header = this.environment.resolvePlaceholders(header); result.add(key, header); } return result; @@ -54,8 +56,8 @@ class SimpleRequestBuilder implements RequestBuilder { @Override public URI uri(String destination) { try { - return new URI(environment - .resolvePlaceholders(baseUrl.replace("${destination}", destination))); + return new URI(this.environment.resolvePlaceholders( + this.baseUrl.replace("${destination}", destination))); } catch (URISyntaxException e) { throw new IllegalStateException("Cannot create URI", e); diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierAutoConfiguration.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierAutoConfiguration.java index 20ab6383b..6657cf027 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierAutoConfiguration.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -68,16 +68,20 @@ class SupplierAutoConfiguration { static class SourceActiveCondition extends AnyNestedCondition { - public SourceActiveCondition() { + SourceActiveCondition() { super(ConfigurationPhase.PARSE_CONFIGURATION); } @ConditionalOnNotWebApplication static class OnNotWebapp { + } @ConditionalOnProperty(prefix = "spring.cloud.function.web.supplier", name = "enabled") static class Enabled { + } + } + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierExporter.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierExporter.java index b571f3a9c..13676b3e7 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierExporter.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierExporter.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,11 @@ import java.util.Collections; import java.util.Set; import java.util.function.Supplier; +import reactor.core.Disposable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; + import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.context.SmartLifecycle; import org.springframework.http.HttpHeaders; @@ -28,11 +33,6 @@ import org.springframework.web.reactive.function.BodyInserters; import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; -import reactor.core.Disposable; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; - /** * Forwards items obtained from a {@link Supplier} or set of suppliers to an external HTTP * endpoint. @@ -62,7 +62,7 @@ class SupplierExporter implements SmartLifecycle { private volatile Disposable subscription; - public SupplierExporter(RequestBuilder requestBuilder, + SupplierExporter(RequestBuilder requestBuilder, DestinationResolver destinationResolver, FunctionCatalog catalog, WebClient client, SupplierProperties props) { this.requestBuilder = requestBuilder; @@ -84,10 +84,10 @@ class SupplierExporter implements SmartLifecycle { this.ok = true; Flux streams = Flux.empty(); - Set names = this.supplier == null ? catalog.getNames(Supplier.class) + Set names = this.supplier == null ? this.catalog.getNames(Supplier.class) : Collections.singleton(this.supplier); for (String name : names) { - Supplier> supplier = catalog.lookup(Supplier.class, name); + Supplier> supplier = this.catalog.lookup(Supplier.class, name); streams = streams.mergeWith(forward(supplier, name)); } @@ -105,13 +105,14 @@ class SupplierExporter implements SmartLifecycle { private Flux forward(Supplier> supplier, String name) { return supplier.get().publishOn(Schedulers.parallel()).flatMap(value -> { - String destination = destinationResolver.destination(supplier, name, value); + String destination = this.destinationResolver.destination(supplier, name, + value); return post(uri(destination), destination, value); }); } private Mono post(URI uri, String destination, Object value) { - Mono result = client.post().uri(uri) + Mono result = this.client.post().uri(uri) .headers(headers -> headers(headers, destination, value)) .body(BodyInserters.fromObject(value)).exchange(); if (this.debug) { @@ -121,11 +122,11 @@ class SupplierExporter implements SmartLifecycle { } private void headers(HttpHeaders headers, String destination, Object value) { - headers.putAll(requestBuilder.headers(destination, value)); + headers.putAll(this.requestBuilder.headers(destination, value)); } private URI uri(String destination) { - return requestBuilder.uri(destination); + return this.requestBuilder.uri(destination); } public boolean isOk() { diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierProperties.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierProperties.java index 4c8fb674c..10ccfd1a4 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierProperties.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/source/SupplierProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -29,10 +29,17 @@ import org.springframework.boot.context.properties.ConfigurationProperties; public class SupplierProperties { private boolean autoStartup = true; + private boolean debug = true; + private String name; + private String templateUrl; + private boolean enabled; + + private Map headers = new LinkedHashMap<>(); + public boolean isEnabled() { return this.enabled; } @@ -41,8 +48,6 @@ public class SupplierProperties { this.enabled = enabled; } - private Map headers = new LinkedHashMap<>(); - public boolean isAutoStartup() { return this.autoStartup; } @@ -59,23 +64,24 @@ public class SupplierProperties { this.debug = debug; } + public String getName() { + return this.name; + } + public void setName(String name) { this.name = name; } - public String getName() { - return this.name; + public String getTemplateUrl() { + return this.templateUrl; } public void setTemplateUrl(String templateUrl) { this.templateUrl = templateUrl; } - public String getTemplateUrl() { - return this.templateUrl; - } - public Map getHeaders() { return this.headers; } + } diff --git a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/util/HeaderUtils.java b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/util/HeaderUtils.java index cb831b972..ccefd1279 100644 --- a/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/util/HeaderUtils.java +++ b/spring-cloud-function-web/src/main/java/org/springframework/cloud/function/web/util/HeaderUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018 the original author or authors. + * Copyright 2012-2019 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. @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.springframework.cloud.function.web.util; import java.util.Arrays; @@ -28,12 +29,16 @@ import org.springframework.messaging.MessageHeaders; * @author Dave Syer * @author Oleg Zhurakousky */ -public class HeaderUtils { +public final class HeaderUtils { private static HttpHeaders IGNORED = new HttpHeaders(); private static HttpHeaders REQUEST_ONLY = new HttpHeaders(); + private HeaderUtils() { + throw new IllegalStateException("Can't instantiate a utility class"); + } + static { IGNORED.add(MessageHeaders.ID, ""); IGNORED.add(HttpHeaders.CONTENT_LENGTH, "0"); @@ -86,4 +91,5 @@ public class HeaderUtils { private static Collection multi(Object value) { return value instanceof Collection ? (Collection) value : Arrays.asList(value); } + } diff --git a/spring-cloud-function-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-function-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 5c6dc17e8..217d1affe 100644 --- a/spring-cloud-function-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-function-web/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,9 +1,11 @@ -{"properties": [ - { - "name": "spring.cloud.function.web.path", - "type": "java.lang.String", - "description": "Path to web resources for functions (should start with / if not empty).", - "defaultValue": "" - }] +{ + "properties": [ + { + "name": "spring.cloud.function.web.path", + "type": "java.lang.String", + "description": "Path to web resources for functions (should start with / if not empty).", + "defaultValue": "" + } + ] } diff --git a/spring-cloud-function-web/src/main/resources/META-INF/spring.factories b/spring-cloud-function-web/src/main/resources/META-INF/spring.factories index 49621b7cc..bf62195c4 100644 --- a/spring-cloud-function-web/src/main/resources/META-INF/spring.factories +++ b/spring-cloud-function-web/src/main/resources/META-INF/spring.factories @@ -2,10 +2,8 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.function.web.flux.ReactorAutoConfiguration,\ org.springframework.cloud.function.web.mvc.ReactorAutoConfiguration,\ org.springframework.cloud.function.web.source.SupplierAutoConfiguration - org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc=\ org.springframework.cloud.function.web.flux.ReactorAutoConfiguration,\ org.springframework.cloud.function.context.config.ContextFunctionCatalogAutoConfiguration - org.springframework.context.ApplicationContextInitializer=\ -org.springframework.cloud.function.web.function.FunctionEndpointInitializer \ No newline at end of file +org.springframework.cloud.function.web.function.FunctionEndpointInitializer diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/flux/FluxRestApplicationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/flux/FluxRestApplicationTests.java index 8a43c0ea9..49996169a 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/flux/FluxRestApplicationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/flux/FluxRestApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -28,6 +28,8 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.reactivestreams.Publisher; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -52,13 +54,10 @@ import org.springframework.web.bind.annotation.RestController; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * Tests for vanilla MVC handling (no function layer). Validates the MVC customizations * that are added in this project independently of the specific concerns of function. - * + * * @author Dave Syer * */ @@ -67,28 +66,31 @@ import reactor.core.publisher.Mono; public class FluxRestApplicationTests { private static final MediaType EVENT_STREAM = MediaType.valueOf("text/event-stream"); + @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; + @Autowired private TestConfiguration test; @Before public void init() { - test.list.clear(); + this.test.list.clear(); } @Test public void wordsSSE() throws Exception { - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(), String.class).getBody()).isEqualTo(sse("foo", "bar")); } @Test public void wordsJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/words")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -97,7 +99,7 @@ public class FluxRestApplicationTests { @Test @Ignore("Fix error handling") public void errorJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/bang")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); @@ -105,7 +107,7 @@ public class FluxRestApplicationTests { @Test public void words() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -113,7 +115,7 @@ public class FluxRestApplicationTests { @Test public void foos() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/foos")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()) @@ -122,7 +124,7 @@ public class FluxRestApplicationTests { @Test public void getMore() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/get/more")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -131,44 +133,44 @@ public class FluxRestApplicationTests { @Test @Ignore("Should this even work? Or do we need to be explicit about the JSON?") public void updates() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.post(new URI("/updates")).body("one\ntwo"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo("onetwo"); } @Test public void updatesJson() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON) .body("[\"one\",\"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo("[\"one\",\"two\"]"); } @Test public void addFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/addFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()) .isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"); } @Test public void timeout() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/timeout")).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); } @Test public void emptyJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/empty")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[]"); @@ -176,22 +178,23 @@ public class FluxRestApplicationTests { @Test public void sentences() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/sentences")).build(), String.class) .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptAny() throws Exception { - assertThat(rest.exchange( - RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(), - String.class).getBody()) - .isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); + assertThat( + this.rest + .exchange(RequestEntity.get(new URI("/sentences")) + .accept(MediaType.ALL).build(), String.class) + .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptJson() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.get(new URI("/sentences")) .accept(MediaType.APPLICATION_JSON).build(), @@ -203,7 +206,7 @@ public class FluxRestApplicationTests { @Test public void uppercase() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/uppercase")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]"); @@ -211,7 +214,7 @@ public class FluxRestApplicationTests { @Test public void uppercaseFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getBody()) @@ -220,7 +223,7 @@ public class FluxRestApplicationTests { @Test public void transform() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/transform")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]"); @@ -228,7 +231,7 @@ public class FluxRestApplicationTests { @Test public void postMore() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/post/more")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]"); @@ -236,21 +239,21 @@ public class FluxRestApplicationTests { @Test public void uppercaseGet() throws Exception { - assertThat(rest.exchange(RequestEntity.get(new URI("/uppercase/foo")) + assertThat(this.rest.exchange(RequestEntity.get(new URI("/uppercase/foo")) .accept(MediaType.TEXT_PLAIN).build(), String.class).getBody()) .isEqualTo("[FOO]"); } @Test public void convertGet() throws Exception { - assertThat(rest.exchange(RequestEntity.get(new URI("/wrap/123")) + assertThat(this.rest.exchange(RequestEntity.get(new URI("/wrap/123")) .accept(MediaType.TEXT_PLAIN).build(), String.class).getBody()) .isEqualTo("..123.."); } @Test public void convertGetJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/entity/321")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("{\"value\":321}"); @@ -259,7 +262,7 @@ public class FluxRestApplicationTests { @Test public void uppercaseJsonStream() throws Exception { assertThat( - rest.exchange( + this.rest.exchange( RequestEntity.post(new URI("/maps")) .contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), @@ -269,7 +272,7 @@ public class FluxRestApplicationTests { @Test public void uppercaseSSE() throws Exception { - assertThat(rest.exchange(RequestEntity.post(new URI("/uppercase")) + assertThat(this.rest.exchange(RequestEntity.post(new URI("/uppercase")) .accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class).getBody()) .isEqualTo(sse("[FOO]", "[BAR]")); @@ -277,9 +280,10 @@ public class FluxRestApplicationTests { @Test public void altSSE() throws Exception { - assertThat(rest.exchange(RequestEntity.post(new URI("/alt")).accept(EVENT_STREAM) - .contentType(MediaType.APPLICATION_JSON).body("[\"foo\",\"bar\"]"), - String.class).getBody()).isEqualTo(sse("[FOO]", "[BAR]")); + assertThat(this.rest.exchange(RequestEntity.post(new URI("/alt")) + .accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON) + .body("[\"foo\",\"bar\"]"), String.class).getBody()) + .isEqualTo(sse("[FOO]", "[BAR]")); } private String sse(String... values) { @@ -396,6 +400,7 @@ public class FluxRestApplicationTests { } public static class Foo { + private String value; public Foo(String value) { @@ -406,11 +411,13 @@ public class FluxRestApplicationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/mvc/MvcRestApplicationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/mvc/MvcRestApplicationTests.java index 3aaff9321..836c747b1 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/mvc/MvcRestApplicationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/mvc/MvcRestApplicationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -27,6 +27,8 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -51,13 +53,10 @@ import org.springframework.web.bind.annotation.RestController; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * Tests for vanilla MVC handling (no function layer). Validates the MVC customizations * that are added in this project independently of the specific concerns of function. - * + * * @author Dave Syer * */ @@ -66,28 +65,31 @@ import reactor.core.publisher.Mono; public class MvcRestApplicationTests { private static final MediaType EVENT_STREAM = MediaType.valueOf("text/event-stream"); + @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; + @Autowired private TestConfiguration test; @Before public void init() { - test.list.clear(); + this.test.list.clear(); } @Test public void wordsSSE() throws Exception { - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(), String.class).getBody()).isEqualTo(sse("foo", "bar")); } @Test public void wordsJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/words")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -96,7 +98,7 @@ public class MvcRestApplicationTests { @Test @Ignore("Fix error handling") public void errorJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/bang")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); @@ -104,7 +106,7 @@ public class MvcRestApplicationTests { @Test public void words() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -112,7 +114,7 @@ public class MvcRestApplicationTests { @Test public void foos() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/foos")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()) @@ -121,7 +123,7 @@ public class MvcRestApplicationTests { @Test public void getMore() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/get/more")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -130,44 +132,44 @@ public class MvcRestApplicationTests { @Test @Ignore("Should this even work? Or do we need to be explicit about the JSON?") public void updates() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.post(new URI("/updates")).body("one\ntwo"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo("onetwo"); } @Test public void updatesJson() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON) .body("[\"one\",\"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo("[\"one\",\"two\"]"); } @Test public void addFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/addFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()) .isEqualTo("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"); } @Test public void timeout() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/timeout")).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); } @Test public void emptyJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/empty")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[]"); @@ -175,22 +177,23 @@ public class MvcRestApplicationTests { @Test public void sentences() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/sentences")).build(), String.class) .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptAny() throws Exception { - assertThat(rest.exchange( - RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(), - String.class).getBody()) - .isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); + assertThat( + this.rest + .exchange(RequestEntity.get(new URI("/sentences")) + .accept(MediaType.ALL).build(), String.class) + .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptJson() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.get(new URI("/sentences")) .accept(MediaType.APPLICATION_JSON).build(), @@ -202,7 +205,7 @@ public class MvcRestApplicationTests { @Test public void uppercase() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/uppercase")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]"); @@ -210,7 +213,7 @@ public class MvcRestApplicationTests { @Test public void uppercaseFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getBody()) @@ -219,7 +222,7 @@ public class MvcRestApplicationTests { @Test public void transform() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/transform")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]"); @@ -227,7 +230,7 @@ public class MvcRestApplicationTests { @Test public void postMore() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/post/more")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"[FOO]\",\"[BAR]\"]"); @@ -235,17 +238,19 @@ public class MvcRestApplicationTests { @Test public void uppercaseGet() { - assertThat(rest.getForObject("/uppercase/foo", String.class)).isEqualTo("[FOO]"); + assertThat(this.rest.getForObject("/uppercase/foo", String.class)) + .isEqualTo("[FOO]"); } @Test public void convertGet() { - assertThat(rest.getForObject("/wrap/123", String.class)).isEqualTo("..123.."); + assertThat(this.rest.getForObject("/wrap/123", String.class)) + .isEqualTo("..123.."); } @Test public void convertGetJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/entity/321")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("{\"value\":321}"); @@ -254,7 +259,7 @@ public class MvcRestApplicationTests { @Test public void uppercaseJsonStream() throws Exception { assertThat( - rest.exchange( + this.rest.exchange( RequestEntity.post(new URI("/maps")) .contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), @@ -264,7 +269,7 @@ public class MvcRestApplicationTests { @Test public void uppercaseSSE() throws Exception { - assertThat(rest.exchange(RequestEntity.post(new URI("/uppercase")) + assertThat(this.rest.exchange(RequestEntity.post(new URI("/uppercase")) .accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class).getBody()) .isEqualTo(sse("[FOO]", "[BAR]")); @@ -374,6 +379,7 @@ public class MvcRestApplicationTests { } public static class Foo { + private String value; public Foo(String value) { @@ -384,11 +390,13 @@ public class MvcRestApplicationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/scan/ComponentTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/scan/ComponentTests.java index eeaf9a9c3..462aed62c 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/scan/ComponentTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/scan/ComponentTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,7 @@ import java.util.function.Function; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -39,8 +40,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -51,20 +50,22 @@ public class ComponentTests { @LocalServerPort private int port; + @Autowired private Greeter greeter; + @Autowired private TestRestTemplate rest; @Test public void contextLoads() throws Exception { - assertThat(greeter).isNotNull(); + assertThat(this.greeter).isNotNull(); } @Test @Ignore("FIXME") public void greeter() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.post(new URI("/greeter")) .contentType(MediaType.TEXT_PLAIN).body("World"), @@ -76,14 +77,17 @@ public class ComponentTests { @SpringBootApplication @ComponentScan protected static class TestConfiguration { + } @Component("greeter") protected static class Greeter implements Function, Flux> { + @Override public Flux apply(Flux flux) { return flux.map(name -> "Hello " + name); } + } } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ExplicitNonFunctionalTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ExplicitNonFunctionalTests.java index 8345d6c67..1fc608870 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ExplicitNonFunctionalTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ExplicitNonFunctionalTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -30,8 +31,6 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @@ -48,16 +47,19 @@ public class ExplicitNonFunctionalTests { @Test public void words() throws Exception { - client.post().uri("/").body(Mono.just("foo"), String.class).exchange() + this.client.post().uri("/").body(Mono.just("foo"), String.class).exchange() .expectStatus().isOk().expectBody(String.class).isEqualTo("FOO"); } @SpringBootConfiguration @EnableAutoConfiguration protected static class TestConfiguration implements Function { + @Override public String apply(String value) { return value.toUpperCase(); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalTests.java index c42319115..32c0a899e 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -28,14 +29,12 @@ import org.springframework.cloud.function.context.test.FunctionalSpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * */ @RunWith(SpringRunner.class) -//Only need web-application-type because MVC is on the classpath +// Only need web-application-type because MVC is on the classpath @FunctionalSpringBootTest("spring.main.web-application-type=reactive") @AutoConfigureWebTestClient public class FunctionalTests { @@ -45,15 +44,18 @@ public class FunctionalTests { @Test public void words() throws Exception { - client.post().uri("/").body(Mono.just("foo"), String.class).exchange() + this.client.post().uri("/").body(Mono.just("foo"), String.class).exchange() .expectStatus().isOk().expectBody(String.class).isEqualTo("FOO"); } @SpringBootConfiguration protected static class TestConfiguration implements Function { + @Override public String apply(String value) { return value.toUpperCase(); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputListTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputListTests.java index b33d32f85..3984169ea 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputListTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputListTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,7 @@ import java.util.stream.Collectors; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -30,8 +31,6 @@ import org.springframework.cloud.function.context.test.FunctionalSpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @@ -46,18 +45,22 @@ public class FunctionalWithInputListTests { @Test public void words() throws Exception { - client.post().uri("/").body(Mono.just("[{\"value\":\"foo\"}, {\"value\":\"bar\"}]"), String.class) + this.client.post().uri("/") + .body(Mono.just("[{\"value\":\"foo\"}, {\"value\":\"bar\"}]"), + String.class) .exchange().expectStatus().isOk().expectBody(String.class) .isEqualTo("{\"value\":\"FOOBAR\"}"); } @SpringBootConfiguration protected static class TestConfiguration implements Function, Foo> { + @Override public Foo apply(List value) { return new Foo(value.stream().map(foo -> foo.getValue().toUpperCase()) .collect(Collectors.joining())); } + } public static class Foo { @@ -85,4 +88,5 @@ public class FunctionalWithInputListTests { } } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputSetTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputSetTests.java index ac3bd7538..cba093dec 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputSetTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/FunctionalWithInputSetTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -16,14 +16,13 @@ package org.springframework.cloud.function.test; -import static org.junit.Assert.assertTrue; - import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -32,7 +31,7 @@ import org.springframework.cloud.function.context.test.FunctionalSpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; +import static org.junit.Assert.assertTrue; /** * @author Dave Syer @@ -48,8 +47,11 @@ public class FunctionalWithInputSetTests { @Test public void words() throws Exception { - String reply = client.post().uri("/").body(Mono.just("[{\"value\":\"foo\"}, {\"value\":\"bar\"}]"), String.class) - .exchange().expectStatus().isOk().expectBody(String.class).returnResult().getResponseBody(); + String reply = this.client.post().uri("/") + .body(Mono.just("[{\"value\":\"foo\"}, {\"value\":\"bar\"}]"), + String.class) + .exchange().expectStatus().isOk().expectBody(String.class).returnResult() + .getResponseBody(); assertTrue(reply.contains("FOO")); assertTrue(reply.contains("BAR")); assertTrue(reply.contains("{\"value\":\"")); @@ -57,11 +59,13 @@ public class FunctionalWithInputSetTests { @SpringBootConfiguration protected static class TestConfiguration implements Function, Foo> { + @Override public Foo apply(Set value) { return new Foo(value.stream().map(foo -> foo.getValue().toUpperCase()) .collect(Collectors.joining())); } + } public static class Foo { @@ -89,4 +93,5 @@ public class FunctionalWithInputSetTests { } } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/HeadersToMessageTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/HeadersToMessageTests.java index 7e4c2145e..619f9f8d5 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/HeadersToMessageTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/HeadersToMessageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -19,6 +19,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -29,10 +30,7 @@ import org.springframework.messaging.support.MessageBuilder; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** - * * @author Oleg Zhurakousky * */ @@ -47,7 +45,7 @@ public class HeadersToMessageTests { @Test public void testBodyAndCustomHeaderFromMessagePropagation() throws Exception { - client.post().uri("/").body(Mono.just("foo"), String.class).exchange() + this.client.post().uri("/").body(Mono.just("foo"), String.class).exchange() .expectStatus().isOk().expectHeader() .valueEquals("x-content-type", "application/xml").expectHeader() .valueEquals("foo", "bar").expectBody(String.class).isEqualTo("FOO"); @@ -56,11 +54,15 @@ public class HeadersToMessageTests { @SpringBootConfiguration protected static class TestConfiguration implements Function, Message> { + public Message apply(Message request) { - Message message = MessageBuilder.withPayload(request.getPayload().toUpperCase()) + Message message = MessageBuilder + .withPayload(request.getPayload().toUpperCase()) .setHeader("X-Content-Type", "application/xml") .setHeader("foo", "bar").build(); return message; } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ImplicitNonFunctionalTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ImplicitNonFunctionalTests.java index f2fdec5bd..d9c4f4c07 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ImplicitNonFunctionalTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/ImplicitNonFunctionalTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -31,8 +32,6 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * @@ -48,16 +47,19 @@ public class ImplicitNonFunctionalTests { @Test public void words() throws Exception { - client.post().uri("/").body(Mono.just("foo"), String.class).exchange() + this.client.post().uri("/").body(Mono.just("foo"), String.class).exchange() .expectStatus().isOk().expectBody(String.class).isEqualTo("FOO"); } @SpringBootConfiguration @EnableAutoConfiguration protected static class TestConfiguration { + @Bean public Function uppercase() { return value -> value.toUpperCase(); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/MoreThenOneFunctionRootMappingTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/MoreThenOneFunctionRootMappingTests.java index 0d8e4405a..851c29891 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/MoreThenOneFunctionRootMappingTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/MoreThenOneFunctionRootMappingTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,8 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -30,8 +32,6 @@ import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** * @author Oleg Zhurakousky * @@ -39,7 +39,7 @@ import reactor.core.publisher.Mono; @RunWith(SpringRunner.class) @SpringBootTest({ "spring.main.web-application-type=REACTIVE", "spring.functional.enabled=false", - "spring.cloud.function.definition=uppercase|reverse"}) + "spring.cloud.function.definition=uppercase|reverse" }) @AutoConfigureWebTestClient @DirtiesContext public class MoreThenOneFunctionRootMappingTests { @@ -49,13 +49,14 @@ public class MoreThenOneFunctionRootMappingTests { @Test public void words() throws Exception { - client.post().uri("/").body(Mono.just("star"), String.class).exchange() + this.client.post().uri("/").body(Mono.just("star"), String.class).exchange() .expectStatus().isOk().expectBody(String.class).isEqualTo("RATS"); } @SpringBootConfiguration @EnableAutoConfiguration protected static class TestConfiguration { + @Bean public Function uppercase() { return v -> v.toUpperCase(); @@ -65,5 +66,7 @@ public class MoreThenOneFunctionRootMappingTests { public Function reverse() { return v -> new StringBuilder(v).reverse().toString(); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/PojoTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/PojoTests.java index 9dba47810..680a22b1d 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/PojoTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/test/PojoTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -20,6 +20,7 @@ import java.util.function.Function; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; @@ -28,14 +29,12 @@ import org.springframework.cloud.function.context.test.FunctionalSpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Mono; - /** * @author Dave Syer * */ @RunWith(SpringRunner.class) -//Only need web-application-type because MVC is on the classpath +// Only need web-application-type because MVC is on the classpath @FunctionalSpringBootTest("spring.main.web-application-type=reactive") @AutoConfigureWebTestClient public class PojoTests { @@ -45,23 +44,30 @@ public class PojoTests { @Test public void single() throws Exception { - client.post().uri("/").body(Mono.just("{\"value\":\"foo\"}"), String.class).exchange() - .expectStatus().isOk().expectBody(String.class).isEqualTo("{\"value\":\"FOO\"}"); + this.client.post().uri("/").body(Mono.just("{\"value\":\"foo\"}"), String.class) + .exchange().expectStatus().isOk().expectBody(String.class) + .isEqualTo("{\"value\":\"FOO\"}"); } @Test public void multiple() throws Exception { - client.post().uri("/").body(Mono.just("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class).exchange() - .expectStatus().isOk().expectBody(String.class).isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]"); + this.client.post().uri("/") + .body(Mono.just("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), + String.class) + .exchange().expectStatus().isOk().expectBody(String.class) + .isEqualTo("[{\"value\":\"FOO\"},{\"value\":\"BAR\"}]"); } @SpringBootConfiguration protected static class TestConfiguration implements Function { + @Override public Foo apply(Foo value) { return new Foo(value.getValue().toUpperCase()); } + } + } class Foo { @@ -88,4 +94,4 @@ class Foo { return "Foo [value=" + this.value + "]"; } -} \ No newline at end of file +} diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HeadersToMessageTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HeadersToMessageTests.java index 1f1b0353d..5589a274c 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HeadersToMessageTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HeadersToMessageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018-2019 the original author or authors. + * Copyright 2012-2019 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. @@ -41,7 +41,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Dave Syer * @author Oleg Zhurakousky * @@ -50,7 +49,7 @@ import static org.junit.Assert.assertTrue; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.cloud.function.web.path=/functions", "spring.main.web-application-type=reactive" }) -@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, TestConfiguration.class }) public class HeadersToMessageTests { @Autowired @@ -59,9 +58,10 @@ public class HeadersToMessageTests { @Test public void testBodyAndCustomHeaderFromMessagePropagation() throws Exception { // test POJO paylod - ResponseEntity postForEntity = rest.exchange(RequestEntity - .post(new URI("/functions/employee")).contentType(MediaType.APPLICATION_JSON) - .body("{\"name\":\"Bob\",\"age\":25}"), String.class); + ResponseEntity postForEntity = this.rest + .exchange(RequestEntity.post(new URI("/functions/employee")) + .contentType(MediaType.APPLICATION_JSON) + .body("{\"name\":\"Bob\",\"age\":25}"), String.class); assertEquals("{\"name\":\"Bob\",\"age\":25}", postForEntity.getBody()); assertTrue(postForEntity.getHeaders().containsKey("x-content-type")); assertEquals("application/xml", @@ -69,9 +69,8 @@ public class HeadersToMessageTests { assertEquals("bar", postForEntity.getHeaders().get("foo").get(0)); // test simple type payload - postForEntity = rest.postForEntity( - new URI("/functions/string"), "{\"name\":\"Bob\",\"age\":25}", - String.class); + postForEntity = this.rest.postForEntity(new URI("/functions/string"), + "{\"name\":\"Bob\",\"age\":25}", String.class); assertEquals("{\"name\":\"Bob\",\"age\":25}", postForEntity.getBody()); assertTrue(postForEntity.getHeaders().containsKey("x-content-type")); assertEquals("application/xml", @@ -82,6 +81,7 @@ public class HeadersToMessageTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean({ "string" }) public Function, Message> functiono() { return request -> { @@ -95,29 +95,39 @@ public class HeadersToMessageTests { @Bean({ "employee" }) public Function, Message> function1() { return request -> { - Message message = MessageBuilder.withPayload(request.getPayload()) + Message message = MessageBuilder + .withPayload(request.getPayload()) .setHeader("X-Content-Type", "application/xml") .setHeader("foo", "bar").build(); return message; }; } + } + @SuppressWarnings("unused") // used by json converter private static class Employee { + private String name; + private int age; public String getName() { - return name; + return this.name; } + public void setName(String name) { this.name = name; } + public int getAge() { - return age; + return this.age; } + public void setAge(int age) { this.age = age; } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpGetIntegrationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpGetIntegrationTests.java index 21b3152d4..40a182fd5 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpGetIntegrationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpGetIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -30,6 +30,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; @@ -53,44 +54,46 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive") -@ContextConfiguration(classes= {RestApplication.class, ApplicationConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class }) public class HttpGetIntegrationTests { private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM; + @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; + @Autowired private ApplicationConfiguration test; @Before public void init() { - test.list.clear(); + this.test.list.clear(); } @Test public void staticResource() { - assertThat(rest.getForObject("/test.html", String.class)).contains("Test"); + assertThat(this.rest.getForObject("/test.html", String.class)) + .contains("Test"); } @Test public void wordsSSE() throws Exception { - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(), String.class).getBody()).isEqualTo(sse("foo", "bar")); } @Test public void wordsJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/words")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -99,7 +102,7 @@ public class HttpGetIntegrationTests { @Test @Ignore("Fix error handling") public void errorJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/bang")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); @@ -107,7 +110,7 @@ public class HttpGetIntegrationTests { @Test public void words() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -115,7 +118,7 @@ public class HttpGetIntegrationTests { @Test public void word() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.get(new URI("/word")).accept(MediaType.TEXT_PLAIN).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); @@ -124,7 +127,7 @@ public class HttpGetIntegrationTests { @Test public void foos() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/foos")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()) @@ -133,7 +136,7 @@ public class HttpGetIntegrationTests { @Test public void getMore() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/get/more")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -141,7 +144,7 @@ public class HttpGetIntegrationTests { @Test public void bareWords() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/bareWords")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -149,7 +152,7 @@ public class HttpGetIntegrationTests { @Test public void timeoutJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/timeout")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); @@ -157,7 +160,7 @@ public class HttpGetIntegrationTests { @Test public void emptyJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/empty")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[]"); @@ -165,22 +168,23 @@ public class HttpGetIntegrationTests { @Test public void sentences() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/sentences")).build(), String.class) .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptAny() throws Exception { - assertThat(rest.exchange( - RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(), - String.class).getBody()) - .isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); + assertThat( + this.rest + .exchange(RequestEntity.get(new URI("/sentences")) + .accept(MediaType.ALL).build(), String.class) + .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptJson() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.get(new URI("/sentences")) .accept(MediaType.APPLICATION_JSON).build(), @@ -192,7 +196,7 @@ public class HttpGetIntegrationTests { @Test public void sentencesAcceptSse() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.get(new URI("/sentences")).accept(EVENT_STREAM).build(), String.class); assertThat(result.getBody()) @@ -203,7 +207,7 @@ public class HttpGetIntegrationTests { @Test public void postMoreFoo() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .get(new URI("/post/more/foo")).accept(MediaType.TEXT_PLAIN).build(), String.class); assertThat(result.getBody()).isEqualTo("(FOO)"); @@ -211,7 +215,7 @@ public class HttpGetIntegrationTests { @Test public void uppercaseGet() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .get(new URI("/uppercase/foo")).accept(MediaType.TEXT_PLAIN).build(), String.class); assertThat(result.getBody()).isEqualTo("(FOO)"); @@ -219,7 +223,7 @@ public class HttpGetIntegrationTests { @Test public void convertGet() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .get(new URI("/wrap/123")).accept(MediaType.TEXT_PLAIN).build(), String.class); assertThat(result.getBody()).isEqualTo("..123.."); @@ -227,13 +231,13 @@ public class HttpGetIntegrationTests { @Test public void supplierFirst() { - assertThat(rest.getForObject("/not/a/function", String.class)) + assertThat(this.rest.getForObject("/not/a/function", String.class)) .isEqualTo("[\"hello\"]"); } @Test public void convertGetJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/entity/321")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("{\"value\":321}"); @@ -339,6 +343,7 @@ public class HttpGetIntegrationTests { } public static class Foo { + private String value; public Foo(String value) { @@ -349,12 +354,13 @@ public class HttpGetIntegrationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpPostIntegrationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpPostIntegrationTests.java index f862590f9..fe97442bb 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpPostIntegrationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/HttpPostIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -29,6 +29,8 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -57,9 +59,6 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer */ @@ -69,23 +68,26 @@ import reactor.core.publisher.Mono; public class HttpPostIntegrationTests { private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM; + @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; + @Autowired private ApplicationConfiguration test; @Before public void init() { - test.list.clear(); + this.test.list.clear(); } @Test public void qualifierFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity.post(new URI("/foos")) - .contentType(MediaType.APPLICATION_JSON).body("[\"foo\",\"bar\"]"), - String.class); + ResponseEntity result = this.rest.exchange(RequestEntity + .post(new URI("/foos")).contentType(MediaType.APPLICATION_JSON) + .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()) .isEqualTo("[{\"value\":\"[FOO]\"},{\"value\":\"[BAR]\"}]"); @@ -93,47 +95,47 @@ public class HttpPostIntegrationTests { @Test public void updates() throws Exception { - ResponseEntity result = rest.exchange( - RequestEntity.post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON).body("[\"one\", \"two\"]"), - String.class); + ResponseEntity result = this.rest.exchange(RequestEntity + .post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON) + .body("[\"one\", \"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isNull(); } @Test public void updatesJson() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON) .body("[\"one\",\"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo(null); } @Test public void addFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/addFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo(null); } @Test public void bareUpdates() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUpdates")).contentType(MediaType.APPLICATION_JSON) .body("[\"one\",\"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo("[]"); } @Test public void uppercase() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/uppercase")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -141,7 +143,7 @@ public class HttpPostIntegrationTests { @Test public void messages() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/messages")).contentType(MediaType.APPLICATION_JSON) .header("x-foo", "bar").body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getHeaders().getFirst("x-foo")).isEqualTo("bar"); @@ -151,7 +153,7 @@ public class HttpPostIntegrationTests { @Test public void headers() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/headers")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getHeaders().getFirst("foo")).isEqualTo("bar"); @@ -161,7 +163,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseSingleValue() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.post(new URI("/uppercase")) .contentType(MediaType.TEXT_PLAIN).body("foo"), @@ -172,7 +174,7 @@ public class HttpPostIntegrationTests { @Test @Ignore("WebFlux would split the request body into lines: TODO make this work the same") public void uppercasePlainText() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.post(new URI("/uppercase")) .contentType(MediaType.TEXT_PLAIN).body("foo\nbar"), String.class); @@ -181,7 +183,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getBody()) @@ -191,7 +193,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseFoo() throws Exception { // Single Foo can be parsed - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON) .body("{\"value\":\"foo\"}"), String.class); assertThat(result.getBody()).isEqualTo("[{\"value\":\"FOO\"}]"); @@ -199,7 +201,7 @@ public class HttpPostIntegrationTests { @Test public void bareUppercaseFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getBody()) @@ -208,18 +210,18 @@ public class HttpPostIntegrationTests { @Test public void typelessFunctionPassingArray() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity - .post(new URI("/typelessFunctionExpectingText")).contentType(MediaType.TEXT_PLAIN) - .body("[{\"value\":\"foo\"}]"), String.class); - assertThat(result.getBody()) - .isEqualTo("[{\"value\":\"foo\"}]"); + ResponseEntity result = this.rest.exchange( + RequestEntity.post(new URI("/typelessFunctionExpectingText")) + .contentType(MediaType.TEXT_PLAIN).body("[{\"value\":\"foo\"}]"), + String.class); + assertThat(result.getBody()).isEqualTo("[{\"value\":\"foo\"}]"); } @Test public void bareUppercaseFoo() throws Exception { // Single Foo can be parsed and returns a single value if the function is defined // that way - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON) .body("{\"value\":\"foo\"}"), String.class); assertThat(result.getBody()).isEqualTo("{\"value\":\"FOO\"}"); @@ -227,7 +229,7 @@ public class HttpPostIntegrationTests { @Test public void bareUppercase() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUppercase")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -235,7 +237,7 @@ public class HttpPostIntegrationTests { @Test public void singleValuedText() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.post(new URI("/bareUppercase")).accept(MediaType.TEXT_PLAIN) .contentType(MediaType.TEXT_PLAIN).body("foo"), String.class); @@ -244,7 +246,7 @@ public class HttpPostIntegrationTests { @Test public void transform() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/transform")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -252,7 +254,7 @@ public class HttpPostIntegrationTests { @Test public void postMore() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/post/more")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -260,8 +262,11 @@ public class HttpPostIntegrationTests { @Test public void convertPost() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity.post(new URI("/wrap")) - .contentType(MediaType.TEXT_PLAIN).body("123"), String.class); + ResponseEntity result = this.rest + .exchange( + RequestEntity.post(new URI("/wrap")) + .contentType(MediaType.TEXT_PLAIN).body("123"), + String.class); // Result is multi-valued so it has to come out as an array assertThat(result.getBody()).isEqualTo("[\"..123..\"]"); } @@ -270,7 +275,7 @@ public class HttpPostIntegrationTests { public void convertPostJson() throws Exception { // If you POST a single value to a Function,Flux> it can't // determine if the output is single valued, so it has to send an array back - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.post(new URI("/doubler")) .contentType(MediaType.TEXT_PLAIN).body("123"), @@ -280,7 +285,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseJsonArray() throws Exception { - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/maps")) .contentType(MediaType.APPLICATION_JSON) // The new line in the middle is optional @@ -291,7 +296,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseSSE() throws Exception { - assertThat(rest.exchange(RequestEntity.post(new URI("/uppercase")) + assertThat(this.rest.exchange(RequestEntity.post(new URI("/uppercase")) .accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class).getBody()) .isEqualTo(sse("(FOO)", "(BAR)")); @@ -305,7 +310,7 @@ public class HttpPostIntegrationTests { map.put("A", Arrays.asList("1", "2", "3")); map.put("B", Arrays.asList("5", "6")); - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/sum")).accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_FORM_URLENCODED).body(map), String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]"); @@ -319,7 +324,7 @@ public class HttpPostIntegrationTests { map.put("A", Arrays.asList("1", "2", "3")); map.put("B", Arrays.asList("5", "6")); - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/sum")).accept(MediaType.APPLICATION_JSON) .contentType(MediaType.MULTIPART_FORM_DATA).body(map), String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]"); @@ -328,7 +333,7 @@ public class HttpPostIntegrationTests { @Test public void count() throws Exception { List list = Arrays.asList("A", "B", "A"); - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/count")).accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).body(list), String.class).getBody()).isEqualTo("{\"A\":2,\"B\":1}"); @@ -390,14 +395,14 @@ public class HttpPostIntegrationTests { return value -> { Assert.isInstanceOf(String.class, value); return value; - }; + }; } -// @Bean -// public Function byteArrayInputFunction() { -//// return value -> new Foo(value.getValue().trim().toUpperCase()); -// throw new UnsupportedOperationException("boom?"); -// } + // @Bean + // public Function byteArrayInputFunction() { + //// return value -> new Foo(value.getValue().trim().toUpperCase()); + // throw new UnsupportedOperationException("boom?"); + // } @Bean public Function, Flux> wrap() { @@ -422,22 +427,22 @@ public class HttpPostIntegrationTests { public Function qualifier() { return value -> { return new Foo("[" + value.trim().toUpperCase() + "]"); - }; + }; } @Bean public Consumer> updates() { - return flux -> flux.subscribe(value -> list.add(value)); + return flux -> flux.subscribe(value -> this.list.add(value)); } @Bean public Consumer> addFoos() { - return flux -> flux.subscribe(value -> list.add(value.getValue())); + return flux -> flux.subscribe(value -> this.list.add(value.getValue())); } @Bean public Consumer bareUpdates() { - return value -> list.add(value); + return value -> this.list.add(value); } @Bean("not/a") @@ -457,9 +462,11 @@ public class HttpPostIntegrationTests { return flux -> flux.collect(HashMap::new, (map, word) -> map.merge(word, 1, Integer::sum)); } + } public static class Foo { + private String value; public Foo(String value) { @@ -470,12 +477,13 @@ public class HttpPostIntegrationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/PrefixTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/PrefixTests.java index d49ad1cee..a96422a7d 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/PrefixTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/PrefixTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -39,8 +40,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -49,17 +48,18 @@ import reactor.core.publisher.Flux; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.main.web-application-type=reactive", "spring.cloud.function.web.path=/functions", "debug" }) -@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, TestConfiguration.class }) public class PrefixTests { @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; @Test public void words() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.get(new URI("/functions/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -67,7 +67,7 @@ public class PrefixTests { @Test public void missing() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); } @@ -75,9 +75,12 @@ public class PrefixTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean({ "words", "get/more" }) public Supplier> words() { return () -> Flux.fromArray(new String[] { "foo", "bar" }); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/SingletonTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/SingletonTests.java index d0ce2006f..634c98ad9 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/SingletonTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/flux/SingletonTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; @@ -44,25 +45,24 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=reactive") -@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, TestConfiguration.class }) public class SingletonTests { @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; @Test public void words() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -71,6 +71,7 @@ public class SingletonTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean public static BeanDefinitionRegistryPostProcessor processor() { return new BeanDefinitionRegistryPostProcessor() { @@ -91,12 +92,16 @@ public class SingletonTests { } }; } + } static class MySupplier implements Supplier> { + @Override public Flux get() { return Flux.just("foo", "bar"); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/DefaultRouteTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/DefaultRouteTests.java index 4e07e9fa1..4c29a6c28 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/DefaultRouteTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/DefaultRouteTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -22,6 +22,7 @@ import java.util.function.Function; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -40,26 +41,25 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "") -@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, TestConfiguration.class }) public class DefaultRouteTests { @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; @Test @Ignore("FIXME") public void explicit() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.post(new URI("/uppercase")).body("foo"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("FOO"); @@ -68,8 +68,8 @@ public class DefaultRouteTests { @Test @Ignore("FIXME") public void implicit() throws Exception { - ResponseEntity result = rest.exchange( - RequestEntity.post(new URI("/")).body("foo"), String.class); + ResponseEntity result = this.rest + .exchange(RequestEntity.post(new URI("/")).body("foo"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("FOO"); } @@ -77,9 +77,12 @@ public class DefaultRouteTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean public Function, Flux> uppercase() { return flux -> flux.map(value -> value.toUpperCase()); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HeadersToMessageTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HeadersToMessageTests.java index 6dfe74568..66619be9b 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HeadersToMessageTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HeadersToMessageTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -43,7 +43,6 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** - * * @author Oleg Zhurakousky * */ @@ -59,9 +58,10 @@ public class HeadersToMessageTests { @Test public void testBodyAndCustomHeaderFromMessagePropagation() throws Exception { - HttpEntity postForEntity = rest.exchange(RequestEntity - .post(new URI("/functions/employee")).contentType(MediaType.APPLICATION_JSON) - .body("{\"name\":\"Bob\",\"age\":25}"), String.class); + HttpEntity postForEntity = this.rest + .exchange(RequestEntity.post(new URI("/functions/employee")) + .contentType(MediaType.APPLICATION_JSON) + .body("{\"name\":\"Bob\",\"age\":25}"), String.class); assertEquals("{\"name\":\"Bob\",\"age\":25}", postForEntity.getBody()); assertTrue(postForEntity.getHeaders().containsKey("x-content-type")); assertEquals("application/xml", @@ -71,9 +71,11 @@ public class HeadersToMessageTests { @Test public void testHeadersPropagatedByDefault() throws Exception { - HttpEntity postForEntity = rest.exchange(RequestEntity - .post(new URI("/functions/vanilla")).contentType(MediaType.APPLICATION_JSON).header("x-context-type", "rubbish") - .body("{\"name\":\"Bob\",\"age\":25}"), String.class); + HttpEntity postForEntity = this.rest + .exchange(RequestEntity.post(new URI("/functions/vanilla")) + .contentType(MediaType.APPLICATION_JSON) + .header("x-context-type", "rubbish") + .body("{\"name\":\"Bob\",\"age\":25}"), String.class); assertEquals("{\"name\":\"Bob\",\"age\":25,\"foo\":\"bar\"}", postForEntity.getBody()); assertTrue(postForEntity.getHeaders().containsKey("x-context-type")); @@ -83,6 +85,7 @@ public class HeadersToMessageTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean({ "employee" }) public Function>, Message>> function() { return request -> { @@ -102,5 +105,7 @@ public class HeadersToMessageTests { return message; }; } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpGetIntegrationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpGetIntegrationTests.java index d1199b79b..8fddbc3b4 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpGetIntegrationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpGetIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -30,6 +30,7 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; @@ -53,44 +54,46 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties="spring.main.web-application-type=servlet") -@ContextConfiguration(classes= {RestApplication.class, ApplicationConfiguration.class}) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=servlet") +@ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class }) public class HttpGetIntegrationTests { private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM; + @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; + @Autowired private ApplicationConfiguration test; @Before public void init() { - test.list.clear(); + this.test.list.clear(); } @Test public void staticResource() { - assertThat(rest.getForObject("/test.html", String.class)).contains("Test"); + assertThat(this.rest.getForObject("/test.html", String.class)) + .contains("Test"); } @Test public void wordsSSE() throws Exception { - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.get(new URI("/words")).accept(EVENT_STREAM).build(), String.class).getBody()).isEqualTo(sse("foo", "bar")); } @Test public void wordsJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/words")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -99,7 +102,7 @@ public class HttpGetIntegrationTests { @Test @Ignore("Fix error handling") public void errorJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/bang")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); @@ -107,7 +110,7 @@ public class HttpGetIntegrationTests { @Test public void words() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -115,7 +118,7 @@ public class HttpGetIntegrationTests { @Test public void word() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/word")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("foo"); @@ -123,7 +126,7 @@ public class HttpGetIntegrationTests { @Test public void foos() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/foos")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()) @@ -132,7 +135,7 @@ public class HttpGetIntegrationTests { @Test public void getMore() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/get/more")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -140,7 +143,7 @@ public class HttpGetIntegrationTests { @Test public void bareWords() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/bareWords")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -148,7 +151,7 @@ public class HttpGetIntegrationTests { @Test public void timeoutJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/timeout")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[\"foo\"]"); @@ -156,7 +159,7 @@ public class HttpGetIntegrationTests { @Test public void emptyJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/empty")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("[]"); @@ -164,22 +167,23 @@ public class HttpGetIntegrationTests { @Test public void sentences() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/sentences")).build(), String.class) .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptAny() throws Exception { - assertThat(rest.exchange( - RequestEntity.get(new URI("/sentences")).accept(MediaType.ALL).build(), - String.class).getBody()) - .isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); + assertThat( + this.rest + .exchange(RequestEntity.get(new URI("/sentences")) + .accept(MediaType.ALL).build(), String.class) + .getBody()).isEqualTo("[[\"go\",\"home\"],[\"come\",\"back\"]]"); } @Test public void sentencesAcceptJson() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.get(new URI("/sentences")) .accept(MediaType.APPLICATION_JSON).build(), @@ -191,7 +195,7 @@ public class HttpGetIntegrationTests { @Test public void sentencesAcceptSse() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.get(new URI("/sentences")).accept(EVENT_STREAM).build(), String.class); assertThat(result.getBody()) @@ -202,28 +206,31 @@ public class HttpGetIntegrationTests { @Test public void postMoreFoo() { - assertThat(rest.getForObject("/post/more/foo", String.class)).isEqualTo("(FOO)"); + assertThat(this.rest.getForObject("/post/more/foo", String.class)) + .isEqualTo("(FOO)"); } @Test public void uppercaseGet() { - assertThat(rest.getForObject("/uppercase/foo", String.class)).isEqualTo("(FOO)"); + assertThat(this.rest.getForObject("/uppercase/foo", String.class)) + .isEqualTo("(FOO)"); } @Test public void convertGet() { - assertThat(rest.getForObject("/wrap/123", String.class)).isEqualTo("..123.."); + assertThat(this.rest.getForObject("/wrap/123", String.class)) + .isEqualTo("..123.."); } @Test public void supplierFirst() { - assertThat(rest.getForObject("/not/a/function", String.class)) + assertThat(this.rest.getForObject("/not/a/function", String.class)) .isEqualTo("[\"hello\"]"); } @Test public void convertGetJson() throws Exception { - assertThat(rest + assertThat(this.rest .exchange(RequestEntity.get(new URI("/entity/321")) .accept(MediaType.APPLICATION_JSON).build(), String.class) .getBody()).isEqualTo("{\"value\":321}"); @@ -329,6 +336,7 @@ public class HttpGetIntegrationTests { } public static class Foo { + private String value; public Foo(String value) { @@ -339,12 +347,13 @@ public class HttpGetIntegrationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpPostIntegrationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpPostIntegrationTests.java index 5d030635b..1b4af66bb 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpPostIntegrationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/HttpPostIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017 the original author or authors. + * Copyright 2012-2019 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. @@ -29,6 +29,8 @@ import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -56,34 +58,35 @@ import org.springframework.util.StringUtils; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; - /** * @author Dave Syer */ @RunWith(SpringRunner.class) -@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties="spring.main.web-application-type=servlet") -@ContextConfiguration(classes= {RestApplication.class, ApplicationConfiguration.class}) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = "spring.main.web-application-type=servlet") +@ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class }) public class HttpPostIntegrationTests { private static final MediaType EVENT_STREAM = MediaType.TEXT_EVENT_STREAM; + @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; + @Autowired private ApplicationConfiguration test; @Before public void init() { - test.list.clear(); + this.test.list.clear(); } + @Test public void qualifierFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity.post(new URI("/foos")) - .contentType(MediaType.APPLICATION_JSON).body("[\"foo\",\"bar\"]"), - String.class); + ResponseEntity result = this.rest.exchange(RequestEntity + .post(new URI("/foos")).contentType(MediaType.APPLICATION_JSON) + .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()) .isEqualTo("[{\"value\":\"[FOO]\"},{\"value\":\"[BAR]\"}]"); @@ -91,48 +94,47 @@ public class HttpPostIntegrationTests { @Test public void updates() throws Exception { - ResponseEntity result = rest.exchange( - RequestEntity.post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON).body("[\"one\", \"two\"]"), - String.class); + ResponseEntity result = this.rest.exchange(RequestEntity + .post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON) + .body("[\"one\", \"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isNull(); } @Test public void updatesJson() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/updates")).contentType(MediaType.APPLICATION_JSON) .body("[\"one\",\"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo(null); } @Test public void addFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/addFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.ACCEPTED); - assertThat(test.list).hasSize(2); - assertThat(result.getBody()) - .isEqualTo(null); + assertThat(this.test.list).hasSize(2); + assertThat(result.getBody()).isEqualTo(null); } @Test public void bareUpdates() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUpdates")).contentType(MediaType.APPLICATION_JSON) .body("[\"one\",\"two\"]"), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(test.list).hasSize(2); + assertThat(this.test.list).hasSize(2); assertThat(result.getBody()).isEqualTo("[]"); } @Test public void uppercase() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/uppercase")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -140,7 +142,7 @@ public class HttpPostIntegrationTests { @Test public void messages() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/messages")).contentType(MediaType.APPLICATION_JSON) // Remove this when Spring 5.0.8 is used .accept(MediaType.valueOf("application/stream+json")) @@ -152,7 +154,7 @@ public class HttpPostIntegrationTests { @Test public void headers() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/headers")).contentType(MediaType.APPLICATION_JSON) // Remove this when Spring 5.0.8 is used .accept(MediaType.valueOf("application/stream+json")) @@ -164,7 +166,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseSingleValue() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.post(new URI("/uppercase")) .contentType(MediaType.TEXT_PLAIN).body("foo"), @@ -176,7 +178,7 @@ public class HttpPostIntegrationTests { @Test @Ignore("WebFlux would split the request body into lines: TODO make this work the same") public void uppercasePlainText() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.post(new URI("/uppercase")) .contentType(MediaType.TEXT_PLAIN).body("foo\nbar"), String.class); @@ -185,7 +187,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getBody()) @@ -195,7 +197,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseFoo() throws Exception { // Single Foo can be parsed - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/upFoos")).contentType(MediaType.APPLICATION_JSON) .body("{\"value\":\"foo\"}"), String.class); assertThat(result.getBody()).isEqualTo("[{\"value\":\"FOO\"}]"); @@ -203,7 +205,7 @@ public class HttpPostIntegrationTests { @Test public void bareUppercaseFoos() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON) .body("[{\"value\":\"foo\"},{\"value\":\"bar\"}]"), String.class); assertThat(result.getBody()) @@ -214,7 +216,7 @@ public class HttpPostIntegrationTests { public void bareUppercaseFoo() throws Exception { // Single Foo can be parsed and returns a single value if the function is defined // that way - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUpFoos")).contentType(MediaType.APPLICATION_JSON) .body("{\"value\":\"foo\"}"), String.class); assertThat(result.getBody()).isEqualTo("{\"value\":\"FOO\"}"); @@ -222,7 +224,7 @@ public class HttpPostIntegrationTests { @Test public void bareUppercase() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/bareUppercase")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -230,7 +232,7 @@ public class HttpPostIntegrationTests { @Test public void singleValuedText() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.post(new URI("/bareUppercase")) .contentType(MediaType.TEXT_PLAIN).body("foo"), @@ -240,7 +242,7 @@ public class HttpPostIntegrationTests { @Test public void transform() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/transform")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -248,7 +250,7 @@ public class HttpPostIntegrationTests { @Test public void postMore() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity + ResponseEntity result = this.rest.exchange(RequestEntity .post(new URI("/post/more")).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class); assertThat(result.getBody()).isEqualTo("[\"(FOO)\",\"(BAR)\"]"); @@ -256,8 +258,11 @@ public class HttpPostIntegrationTests { @Test public void convertPost() throws Exception { - ResponseEntity result = rest.exchange(RequestEntity.post(new URI("/wrap")) - .contentType(MediaType.TEXT_PLAIN).body("123"), String.class); + ResponseEntity result = this.rest + .exchange( + RequestEntity.post(new URI("/wrap")) + .contentType(MediaType.TEXT_PLAIN).body("123"), + String.class); // Result is multi-valued so it has to come out as an array assertThat(result.getBody()).isEqualTo("[\"..123..\"]"); } @@ -266,7 +271,7 @@ public class HttpPostIntegrationTests { public void convertPostJson() throws Exception { // If you POST a single value to a Function,Flux> it can't // determine if the output is single valued, so it has to send an array back - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange( RequestEntity.post(new URI("/doubler")) .contentType(MediaType.TEXT_PLAIN).body("123"), @@ -276,7 +281,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseJsonArray() throws Exception { - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/maps")) .contentType(MediaType.APPLICATION_JSON) // The new line in the middle is optional @@ -287,7 +292,7 @@ public class HttpPostIntegrationTests { @Test public void uppercaseSSE() throws Exception { - assertThat(rest.exchange(RequestEntity.post(new URI("/uppercase")) + assertThat(this.rest.exchange(RequestEntity.post(new URI("/uppercase")) .accept(EVENT_STREAM).contentType(MediaType.APPLICATION_JSON) .body("[\"foo\",\"bar\"]"), String.class).getBody()) .isEqualTo(sse("(FOO)", "(BAR)")); @@ -301,7 +306,7 @@ public class HttpPostIntegrationTests { map.put("A", Arrays.asList("1", "2", "3")); map.put("B", Arrays.asList("5", "6")); - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/sum")).accept(MediaType.APPLICATION_JSON) .contentType(MediaType.MULTIPART_FORM_DATA).body(map), String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]"); @@ -315,7 +320,7 @@ public class HttpPostIntegrationTests { map.put("A", Arrays.asList("1", "2", "3")); map.put("B", Arrays.asList("5", "6")); - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/sum")).accept(MediaType.APPLICATION_JSON) .contentType(MediaType.MULTIPART_FORM_DATA).body(map), String.class).getBody()).isEqualTo("[{\"A\":6,\"B\":11}]"); @@ -324,7 +329,7 @@ public class HttpPostIntegrationTests { @Test public void count() throws Exception { List list = Arrays.asList("A", "B", "A"); - assertThat(rest.exchange( + assertThat(this.rest.exchange( RequestEntity.post(new URI("/count")).accept(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON).body(list), String.class).getBody()).isEqualTo("{\"A\":2,\"B\":1}"); @@ -407,17 +412,17 @@ public class HttpPostIntegrationTests { @Bean public Consumer> updates() { - return flux -> flux.subscribe(value -> list.add(value)); + return flux -> flux.subscribe(value -> this.list.add(value)); } @Bean public Consumer> addFoos() { - return flux -> flux.subscribe(value -> list.add(value.getValue())); + return flux -> flux.subscribe(value -> this.list.add(value.getValue())); } @Bean public Consumer bareUpdates() { - return value -> list.add(value); + return value -> this.list.add(value); } @Bean("not/a") @@ -437,9 +442,11 @@ public class HttpPostIntegrationTests { return flux -> flux.collect(HashMap::new, (map, word) -> map.merge(word, 1, Integer::sum)); } + } public static class Foo { + private String value; public Foo(String value) { @@ -450,12 +457,13 @@ public class HttpPostIntegrationTests { } public String getValue() { - return value; + return this.value; } public void setValue(String value) { this.value = value; } + } } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/PrefixTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/PrefixTests.java index 5437d40c9..9004e961c 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/PrefixTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/PrefixTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; @@ -39,8 +40,6 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * @@ -49,17 +48,18 @@ import reactor.core.publisher.Flux; @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "spring.main.web-application-type=servlet", "spring.cloud.function.web.path=/functions" }) -@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, TestConfiguration.class }) public class PrefixTests { @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; @Test public void words() throws Exception { - ResponseEntity result = rest.exchange( + ResponseEntity result = this.rest.exchange( RequestEntity.get(new URI("/functions/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); @@ -67,7 +67,7 @@ public class PrefixTests { @Test public void missing() throws Exception { - ResponseEntity result = rest + ResponseEntity result = this.rest .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.NOT_FOUND); } @@ -75,9 +75,12 @@ public class PrefixTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean({ "words", "get/more" }) public Supplier> words() { return () -> Flux.fromArray(new String[] { "foo", "bar" }); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/SingletonTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/SingletonTests.java index 4cc81995b..0d5b191bd 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/SingletonTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/mvc/SingletonTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2019 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. @@ -21,6 +21,7 @@ import java.util.function.Supplier; import org.junit.Test; import org.junit.runner.RunWith; +import reactor.core.publisher.Flux; import org.springframework.beans.BeansException; import org.springframework.beans.factory.annotation.Autowired; @@ -44,26 +45,25 @@ import org.springframework.test.context.junit4.SpringRunner; import static org.assertj.core.api.Assertions.assertThat; -import reactor.core.publisher.Flux; - /** * @author Dave Syer * */ @RunWith(SpringRunner.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) -@ContextConfiguration(classes= {RestApplication.class, TestConfiguration.class}) +@ContextConfiguration(classes = { RestApplication.class, TestConfiguration.class }) public class SingletonTests { @LocalServerPort private int port; + @Autowired private TestRestTemplate rest; @Test public void words() throws Exception { - ResponseEntity result = rest.exchange( - RequestEntity.get(new URI("/words")).build(), String.class); + ResponseEntity result = this.rest + .exchange(RequestEntity.get(new URI("/words")).build(), String.class); assertThat(result.getStatusCode()).isEqualTo(HttpStatus.OK); assertThat(result.getBody()).isEqualTo("[\"foo\",\"bar\"]"); } @@ -71,6 +71,7 @@ public class SingletonTests { @EnableAutoConfiguration @org.springframework.boot.test.context.TestConfiguration protected static class TestConfiguration { + @Bean public static BeanDefinitionRegistryPostProcessor processor() { return new BeanDefinitionRegistryPostProcessor() { @@ -85,17 +86,22 @@ public class SingletonTests { public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry registry) throws BeansException { // Simulates what happens when you add a compiled function - RootBeanDefinition beanDefinition = new RootBeanDefinition(MySupplier.class); + RootBeanDefinition beanDefinition = new RootBeanDefinition( + MySupplier.class); registry.registerBeanDefinition("words", beanDefinition); } }; } + } - + static class MySupplier implements Supplier> { + @Override public Flux get() { return Flux.just("foo", "bar"); } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/SourceAutoConfigurationIntegrationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/SourceAutoConfigurationIntegrationTests.java index d50fc3d11..3c54039a2 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/SourceAutoConfigurationIntegrationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/SourceAutoConfigurationIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -49,21 +49,24 @@ public class SourceAutoConfigurationIntegrationTests { @Test public void fails() throws Exception { int count = 0; - while(forwarder.isRunning() && count++<100) { + while (this.forwarder.isRunning() && count++ < 100) { Thread.sleep(20); } // It completed - assertThat(forwarder.isRunning()).isFalse(); + assertThat(this.forwarder.isRunning()).isFalse(); // But failed - assertThat(forwarder.isOk()).isFalse(); + assertThat(this.forwarder.isOk()).isFalse(); } @EnableAutoConfiguration @TestConfiguration public static class ApplicationConfiguration { + @Bean public Supplier word() { return () -> "foo"; } + } + } diff --git a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/WebAppIntegrationTests.java b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/WebAppIntegrationTests.java index 521601d57..fcd53f278 100644 --- a/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/WebAppIntegrationTests.java +++ b/spring-cloud-function-web/src/test/java/org/springframework/cloud/function/web/source/WebAppIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 the original author or authors. + * Copyright 2012-2019 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. @@ -54,12 +54,12 @@ import static org.assertj.core.api.Assertions.assertThat; // in a webapp we have to explicitly enable the export "spring.cloud.function.web.supplier.enabled=true", // manually so we know the webapp is listening when we start - "spring.cloud.function.web.supplier.autoStartup=false"}) + "spring.cloud.function.web.supplier.autoStartup=false" }) @ContextConfiguration(classes = { RestApplication.class, ApplicationConfiguration.class }) public class WebAppIntegrationTests { - + private static Log logger = LogFactory.getLog(WebAppIntegrationTests.class); - + @Autowired private SupplierExporter forwarder; @@ -68,16 +68,18 @@ public class WebAppIntegrationTests { @Test public void posts() throws Exception { - forwarder.start(); - app.latch.await(10, TimeUnit.SECONDS); - assertThat(app.values).hasSize(1); + this.forwarder.start(); + this.app.latch.await(10, TimeUnit.SECONDS); + assertThat(this.app.values).hasSize(1); } @EnableAutoConfiguration @TestConfiguration @RestController public static class ApplicationConfiguration { + private List values = new ArrayList<>(); + private CountDownLatch latch = new CountDownLatch(1); @Bean @@ -89,9 +91,11 @@ public class WebAppIntegrationTests { @PostMapping("/values") public String value(@RequestBody String body) { logger.info("Body: " + body); - values.add(body); - latch.countDown(); + this.values.add(body); + this.latch.countDown(); return "ok"; } + } + } diff --git a/spring-cloud-function-web/src/test/resources/static/test.html b/spring-cloud-function-web/src/test/resources/static/test.html index 9ca4440f5..d64d7739a 100644 --- a/spring-cloud-function-web/src/test/resources/static/test.html +++ b/spring-cloud-function-web/src/test/resources/static/test.html @@ -1 +1,3 @@ -Test \ No newline at end of file + +Test + diff --git a/spring-cloud-starter-function-web/pom.xml b/spring-cloud-starter-function-web/pom.xml index d1819249d..ca8f76270 100644 --- a/spring-cloud-starter-function-web/pom.xml +++ b/spring-cloud-starter-function-web/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 org.springframework.cloud diff --git a/spring-cloud-starter-function-webflux/pom.xml b/spring-cloud-starter-function-webflux/pom.xml index ce02c9596..1d02e27ba 100644 --- a/spring-cloud-starter-function-webflux/pom.xml +++ b/spring-cloud-starter-function-webflux/pom.xml @@ -1,6 +1,7 @@ - + 4.0.0 org.springframework.cloud