From 0f38ea47b8a3f3665111cfa04c7e5dc028437828 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Thu, 12 Dec 2019 15:03:48 +0100 Subject: [PATCH] GGH-431 Fixed discovery of a start class - Ensured that FunctionClassUtils performs additional check to ensure that located star class is SpringBootApplication - Added additional lookup to look for Main-Class if nothing was found in Start-Class primarily to support Azure - Updated Azure samples - Updated documentation Resolves #431 --- .../main/asciidoc/adapters/azure-intro.adoc | 12 ++++----- .../function/utils/FunctionClassUtils.java | 26 +++++++++---------- .../function-sample-azure/pom.xml | 9 +++---- .../src/main/azure/host.json | 3 ++- .../src/main/java/example/Config.java | 2 -- .../src/main/java/example/FooHandler.java | 10 ++++--- 6 files changed, 30 insertions(+), 32 deletions(-) diff --git a/docs/src/main/asciidoc/adapters/azure-intro.adoc b/docs/src/main/asciidoc/adapters/azure-intro.adoc index 78c34e868..cc9fd8473 100644 --- a/docs/src/main/asciidoc/adapters/azure-intro.adoc +++ b/docs/src/main/asciidoc/adapters/azure-intro.adoc @@ -15,12 +15,10 @@ Example: ```java public class FooHandler extends AzureSpringBootRequestHandler { @FunctionName("uppercase") - public Bar execute( - @HttpTrigger(name = "req", methods = { HttpMethod.GET, - HttpMethod.POST }, authLevel = AuthorizationLevel.ANONYMOUS) - Foo foo, - ExecutionContext context) { - return handleRequest(foo, context); + public Bar execute(@HttpTrigger(name = "req", methods = {HttpMethod.GET, + HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, + ExecutionContext context) { + return handleRequest(request.getBody().get(), context); } } ``` @@ -125,7 +123,7 @@ You can run the sample locally, just like the other Spring Cloud Function sample ./mvnw spring-boot:run --- -and `curl -H "Content-Type: text/plain" localhost:8080/function -d '{"value": "hello foobar"}'`. +and `curl -H "Content-Type: text/plain" localhost:8080/api/uppercase -d '{"value": "hello foobar"}'`. You will need the `az` CLI app (see https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-java-maven for more detail). To deploy the function on Azure runtime: diff --git a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/utils/FunctionClassUtils.java b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/utils/FunctionClassUtils.java index 26ee4e24c..ef7533dd2 100644 --- a/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/utils/FunctionClassUtils.java +++ b/spring-cloud-function-context/src/main/java/org/springframework/cloud/function/utils/FunctionClassUtils.java @@ -17,7 +17,6 @@ package org.springframework.cloud.function.utils; import java.io.InputStream; -import java.net.JarURLConnection; import java.net.URL; import java.util.Collections; import java.util.List; @@ -27,8 +26,10 @@ import java.util.jar.Manifest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; /** * General utility class which aggregates various class-level utility functions @@ -93,15 +94,20 @@ public final class FunctionClassUtils { try { logger.info("Searching manifest: " + url); - Manifest manifest; InputStream inputStream = null; try { - if ("jar".equals(url.getProtocol())) { - JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); - manifest = jarConnection.getManifest(); + Manifest manifest = new Manifest(url.openStream()); + String startClassName = manifest.getMainAttributes().getValue("Start-Class"); + if (!StringUtils.hasText(startClassName)) { + startClassName = manifest.getMainAttributes().getValue("Main-Class"); } - else { - manifest = new Manifest(url.openStream()); + + if (StringUtils.hasText(startClassName)) { + Class startClass = ClassUtils.forName(startClassName, FunctionClassUtils.class.getClassLoader()); + if (startClass.getDeclaredAnnotation(SpringBootApplication.class) != null) { + logger.info("Loaded Start Class: " + startClass); + return startClass; + } } } finally { @@ -109,12 +115,6 @@ public final class FunctionClassUtils { inputStream.close(); } } - - String startClass = manifest.getMainAttributes().getValue("Start-Class"); - if (startClass != null) { - return ClassUtils.forName(startClass, FunctionClassUtils.class.getClassLoader()); - } - } catch (Exception ex) { logger.debug("Failed to determine Start-Class in manifest file of " + url, ex); diff --git a/spring-cloud-function-samples/function-sample-azure/pom.xml b/spring-cloud-function-samples/function-sample-azure/pom.xml index 3b6b0944b..8434f93ce 100644 --- a/spring-cloud-function-samples/function-sample-azure/pom.xml +++ b/spring-cloud-function-samples/function-sample-azure/pom.xml @@ -25,10 +25,9 @@ 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 + 1.0.23.RELEASE @@ -55,7 +54,7 @@ org.springframework.cloud spring-cloud-function-dependencies - 2.2.0.BUILD-SNAPSHOT + 3.0.1.BUILD-SNAPSHOT pom import @@ -92,7 +91,7 @@ com.microsoft.azure azure-functions-maven-plugin - 1.0.0-beta-7 + 1.3.4 javax.xml.bind diff --git a/spring-cloud-function-samples/function-sample-azure/src/main/azure/host.json b/spring-cloud-function-samples/function-sample-azure/src/main/azure/host.json index 4ded8af71..cfb16c7ce 100644 --- a/spring-cloud-function-samples/function-sample-azure/src/main/azure/host.json +++ b/spring-cloud-function-samples/function-sample-azure/src/main/azure/host.json @@ -1,3 +1,4 @@ { - "functionTimeout": "00:10:00" + "functionTimeout": "00:05:00", + "version": "2.0" } 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 02cab267e..d516e1c0b 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 @@ -22,7 +22,6 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; -// @checkstyle:off @SpringBootApplication public class Config { @@ -36,7 +35,6 @@ public class Config { } } -// @checkstyle:on class Foo { 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 d7e207f5e..aba291911 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 @@ -18,10 +18,13 @@ package example; import com.microsoft.azure.functions.ExecutionContext; import com.microsoft.azure.functions.HttpMethod; +import com.microsoft.azure.functions.HttpRequestMessage; import com.microsoft.azure.functions.annotation.AuthorizationLevel; import com.microsoft.azure.functions.annotation.FunctionName; import com.microsoft.azure.functions.annotation.HttpTrigger; +import java.util.Optional; + import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHandler; /** @@ -30,11 +33,10 @@ import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHa public class FooHandler extends AzureSpringBootRequestHandler { @FunctionName("uppercase") - public Bar execute( - @HttpTrigger(name = "req", methods = {HttpMethod.GET, - HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) Foo foo, + public Bar execute(@HttpTrigger(name = "req", methods = {HttpMethod.GET, + HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage> request, ExecutionContext context) { - return handleRequest(foo, context); + return handleRequest(request.getBody().get(), context); } }