diff --git a/.gitignore b/.gitignore
index 8f6b9d359..2aa1654c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,9 @@
*.jar
*.war
*.ear
+*.project
+*.classpath
+*.settings
# Idea project files
.idea/
diff --git a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java
index 9647aad2f..46ccfb13b 100644
--- a/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java
+++ b/aws-serverless-java-container-springboot3/src/main/java/com/amazonaws/serverless/proxy/spring/SpringDelegatingLambdaContainerHandler.java
@@ -3,13 +3,27 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.URL;
import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.jar.JarFile;
+import java.util.jar.Manifest;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.cloud.function.serverless.web.FunctionClassUtils;
import org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest;
import org.springframework.cloud.function.serverless.web.ProxyMvc;
+import org.springframework.core.KotlinDetector;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.util.Assert;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
import com.amazonaws.serverless.proxy.AwsHttpApiV2SecurityContextWriter;
import com.amazonaws.serverless.proxy.AwsProxySecurityContextWriter;
@@ -48,6 +62,8 @@
*/
public class SpringDelegatingLambdaContainerHandler implements RequestStreamHandler {
+ private static Log logger = LogFactory.getLog(SpringDelegatingLambdaContainerHandler.class);
+
private final Class>[] startupClasses;
private final ProxyMvc mvc;
@@ -56,6 +72,10 @@ public class SpringDelegatingLambdaContainerHandler implements RequestStreamHand
private final AwsProxyHttpServletResponseWriter responseWriter;
+ public SpringDelegatingLambdaContainerHandler() {
+ this(new Class[] {FunctionClassUtils.getStartClass()});
+ }
+
public SpringDelegatingLambdaContainerHandler(Class>... startupClasses) {
this.startupClasses = startupClasses;
this.mvc = ProxyMvc.INSTANCE(this.startupClasses);
@@ -84,15 +104,17 @@ public void handleRequest(InputStream input, OutputStream output, Context lambda
}
}
-
@SuppressWarnings({ "unchecked", "rawtypes" })
private HttpServletRequest generateRequest(Map request, Context lambdaContext, SecurityContextWriter securityWriter) {
AwsProxyRequest v1Request = this.mapper.convertValue(request, AwsProxyRequest.class);
ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
v1Request.getHttpMethod(), v1Request.getPath());
- httpRequest.setContentType("application/json");
- httpRequest.setContent(v1Request.getBody().getBytes(StandardCharsets.UTF_8));
+
+ if (StringUtils.hasText(v1Request.getBody())) {
+ httpRequest.setContentType("application/json");
+ httpRequest.setContent(v1Request.getBody().getBytes(StandardCharsets.UTF_8));
+ }
httpRequest.setAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY, v1Request.getRequestContext());
httpRequest.setAttribute(RequestReader.API_GATEWAY_STAGE_VARS_PROPERTY, v1Request.getStageVariables());
httpRequest.setAttribute(RequestReader.API_GATEWAY_EVENT_PROPERTY, v1Request);
@@ -107,8 +129,11 @@ public HttpServletRequest generateRequest2(Map request, Context lambdaContext, S
HttpApiV2ProxyRequest v2Request = this.mapper.convertValue(request, HttpApiV2ProxyRequest.class);
ProxyHttpServletRequest httpRequest = new ProxyHttpServletRequest(this.mvc.getApplicationContext().getServletContext(),
v2Request.getRequestContext().getHttp().getMethod(), v2Request.getRequestContext().getHttp().getPath());
- httpRequest.setContentType("application/json");
- httpRequest.setContent(v2Request.getBody().getBytes(StandardCharsets.UTF_8));
+
+ if (StringUtils.hasText(v2Request.getBody())) {
+ httpRequest.setContentType("application/json");
+ httpRequest.setContent(v2Request.getBody().getBytes(StandardCharsets.UTF_8));
+ }
httpRequest.setAttribute(RequestReader.HTTP_API_CONTEXT_PROPERTY, v2Request.getRequestContext());
httpRequest.setAttribute(RequestReader.HTTP_API_STAGE_VARS_PROPERTY, v2Request.getStageVariables());
httpRequest.setAttribute(RequestReader.HTTP_API_EVENT_PROPERTY, v2Request);
diff --git a/samples/springboot3/alt-pet-store/README.md b/samples/springboot3/alt-pet-store/README.md
new file mode 100644
index 000000000..d8cf8383d
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/README.md
@@ -0,0 +1,39 @@
+# Serverless Spring Boot 3 example
+A basic pet store written with the [Spring Boot 3 framework](https://projects.spring.io/spring-boot/). Unlike older examples, this example is relying on the new
+`SpringDelegatingLambdaContainerHandler`, which you simply need to identify as a _handler_ of the Lambda function. The main configuration class identified as `MAIN_CLASS`
+environment variable or `Start-Class` or `Main-Class` entry in Manifest file. See provided `template.yml` file for reference.
+
+
+The application can be deployed in an AWS account using the [Serverless Application Model](https://github.com/awslabs/serverless-application-model). The `template.yml` file in the root folder contains the application definition.
+
+## Pre-requisites
+* [AWS CLI](https://aws.amazon.com/cli/)
+* [SAM CLI](https://github.com/awslabs/aws-sam-cli)
+* [Gradle](https://gradle.org/) or [Maven](https://maven.apache.org/)
+
+## Deployment
+In a shell, navigate to the sample's folder and use the SAM CLI to build a deployable package
+```
+$ sam build
+```
+
+This command compiles the application and prepares a deployment package in the `.aws-sam` sub-directory.
+
+To deploy the application in your AWS account, you can use the SAM CLI's guided deployment process and follow the instructions on the screen
+
+```
+$ sam deploy --guided
+```
+
+Once the deployment is completed, the SAM CLI will print out the stack's outputs, including the new application URL. You can use `curl` or a web browser to make a call to the URL
+
+```
+...
+---------------------------------------------------------------------------------------------------------
+OutputKey-Description OutputValue
+---------------------------------------------------------------------------------------------------------
+PetStoreApi - URL for application https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/pets
+---------------------------------------------------------------------------------------------------------
+
+$ curl https://xxxxxxxxxx.execute-api.us-west-2.amazonaws.com/pets
+```
\ No newline at end of file
diff --git a/samples/springboot3/alt-pet-store/builds.gradle b/samples/springboot3/alt-pet-store/builds.gradle
new file mode 100644
index 000000000..00a9d3a1f
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/builds.gradle
@@ -0,0 +1,29 @@
+apply plugin: 'java'
+
+repositories {
+ mavenLocal()
+ mavenCentral()
+ maven {url "https://repo.spring.io/milestone"}
+ maven {url "https://repo.spring.io/snapshot"}
+}
+
+dependencies {
+ implementation (
+ implementation('org.springframework.boot:spring-boot-starter-web:3.1.1') {
+ exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
+ },
+ 'com.amazonaws.serverless:aws-serverless-java-container-springboot3:[2.0-SNAPSHOT,)',
+ )
+}
+
+task buildZip(type: Zip) {
+ from compileJava
+ from processResources
+ into('lib') {
+ from(configurations.compileClasspath) {
+ exclude 'tomcat-embed-*'
+ }
+ }
+}
+
+build.dependsOn buildZip
diff --git a/samples/springboot3/alt-pet-store/pom.xml b/samples/springboot3/alt-pet-store/pom.xml
new file mode 100644
index 000000000..a8f6220b5
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/pom.xml
@@ -0,0 +1,154 @@
+
+
+ 4.0.0
+
+ com.amazonaws.serverless.sample
+ petstore-springboot3-example
+ 2.0-SNAPSHOT
+ Spring Boot example for the aws-serverless-java-container library
+ Simple pet store written with the Spring framework and Spring Boot
+ https://aws.amazon.com/lambda/
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.1.1
+
+
+
+
+ The Apache Software License, Version 2.0
+ http://www.apache.org/licenses/LICENSE-2.0.txt
+ repo
+
+
+
+
+ 17
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.springframework.boot
+ spring-boot-starter-tomcat
+
+
+
+
+
+ com.amazonaws.serverless
+ aws-serverless-java-container-springboot3
+ 2.0.0-SNAPSHOT
+
+
+
+
+
+ shaded-jar
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.5.0
+
+ false
+
+
+
+ package
+
+ shade
+
+
+
+
+ org.apache.tomcat.embed:*
+
+
+
+
+
+
+
+
+
+
+ assembly-zip
+
+ true
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.3.0
+
+
+ default-jar
+ none
+
+
+
+
+ org.apache.maven.plugins
+ maven-install-plugin
+ 3.1.1
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.6.0
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+ ${project.build.directory}/lib
+ runtime
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+ 3.6.0
+
+
+ zip-assembly
+ package
+
+ single
+
+
+ ${project.artifactId}-${project.version}
+
+ src${file.separator}assembly${file.separator}bin.xml
+
+ false
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/springboot3/alt-pet-store/src/assembly/bin.xml b/samples/springboot3/alt-pet-store/src/assembly/bin.xml
new file mode 100644
index 000000000..1e085057d
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/assembly/bin.xml
@@ -0,0 +1,27 @@
+
+ lambda-package
+
+ zip
+
+ false
+
+
+
+ ${project.build.directory}${file.separator}lib
+ lib
+
+ tomcat-embed*
+
+
+
+
+ ${project.build.directory}${file.separator}classes
+
+ **
+
+ ${file.separator}
+
+
+
\ No newline at end of file
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/Application.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/Application.java
new file mode 100644
index 000000000..ee9989df5
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/Application.java
@@ -0,0 +1,51 @@
+package com.amazonaws.serverless.sample.springboot3;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.web.servlet.HandlerAdapter;
+import org.springframework.web.servlet.HandlerMapping;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+
+import com.amazonaws.serverless.sample.springboot3.controller.PetsController;
+import com.amazonaws.serverless.sample.springboot3.filter.CognitoIdentityFilter;
+
+import jakarta.servlet.Filter;
+
+
+@SpringBootApplication
+@Import({ PetsController.class })
+public class Application {
+
+ // silence console logging
+ @Value("${logging.level.root:OFF}")
+ String message = "";
+
+ /*
+ * Create required HandlerMapping, to avoid several default HandlerMapping instances being created
+ */
+ @Bean
+ public HandlerMapping handlerMapping() {
+ return new RequestMappingHandlerMapping();
+ }
+
+ /*
+ * Create required HandlerAdapter, to avoid several default HandlerAdapter instances being created
+ */
+ @Bean
+ public HandlerAdapter handlerAdapter() {
+ return new RequestMappingHandlerAdapter();
+ }
+
+ @Bean("CognitoIdentityFilter")
+ public Filter cognitoFilter() {
+ return new CognitoIdentityFilter();
+ }
+
+ public static void main(String[] args) {
+ SpringApplication.run(Application.class, args);
+ }
+}
\ No newline at end of file
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/controller/PetsController.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/controller/PetsController.java
new file mode 100644
index 000000000..680e629d3
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/controller/PetsController.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 com.amazonaws.serverless.sample.springboot3.controller;
+
+
+
+import com.amazonaws.serverless.sample.springboot3.model.Pet;
+import com.amazonaws.serverless.sample.springboot3.model.PetData;
+
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+
+import java.security.Principal;
+import java.util.Optional;
+import java.util.UUID;
+
+
+@RestController
+@EnableWebMvc
+public class PetsController {
+ @RequestMapping(path = "/pets", method = RequestMethod.POST)
+ public Pet createPet(@RequestBody Pet newPet) {
+ if (newPet.getName() == null || newPet.getBreed() == null) {
+ return null;
+ }
+
+ Pet dbPet = newPet;
+ dbPet.setId(UUID.randomUUID().toString());
+ return dbPet;
+ }
+
+ @RequestMapping(path = "/pets", method = RequestMethod.GET)
+ public Pet[] listPets(@RequestParam("limit") Optional limit, Principal principal) {
+ int queryLimit = 10;
+ if (limit.isPresent()) {
+ queryLimit = limit.get();
+ }
+
+ Pet[] outputPets = new Pet[queryLimit];
+
+ for (int i = 0; i < queryLimit; i++) {
+ Pet newPet = new Pet();
+ newPet.setId(UUID.randomUUID().toString());
+ newPet.setName(PetData.getRandomName());
+ newPet.setBreed(PetData.getRandomBreed());
+ newPet.setDateOfBirth(PetData.getRandomDoB());
+ outputPets[i] = newPet;
+ }
+
+ return outputPets;
+ }
+
+ @RequestMapping(path = "/pets/{petId}", method = RequestMethod.GET)
+ public Pet listPets() {
+ Pet newPet = new Pet();
+ newPet.setId(UUID.randomUUID().toString());
+ newPet.setBreed(PetData.getRandomBreed());
+ newPet.setDateOfBirth(PetData.getRandomDoB());
+ newPet.setName(PetData.getRandomName());
+ return newPet;
+ }
+
+}
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
new file mode 100644
index 000000000..d6ccae765
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/filter/CognitoIdentityFilter.java
@@ -0,0 +1,69 @@
+package com.amazonaws.serverless.sample.springboot3.filter;
+
+
+import com.amazonaws.serverless.proxy.RequestReader;
+import com.amazonaws.serverless.proxy.model.AwsProxyRequestContext;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+import java.io.IOException;
+
+
+/**
+ * Simple Filter implementation that looks for a Cognito identity id in the API Gateway request context
+ * and stores the value in a request attribute. The filter is registered with aws-serverless-java-container
+ * in the onStartup method from the {@link com.amazonaws.serverless.sample.springboot3.StreamLambdaHandler} class.
+ */
+public class CognitoIdentityFilter implements Filter {
+ public static final String COGNITO_IDENTITY_ATTRIBUTE = "com.amazonaws.serverless.cognitoId";
+
+ private static Logger log = LoggerFactory.getLogger(CognitoIdentityFilter.class);
+
+ @Override
+ public void init(FilterConfig filterConfig)
+ throws ServletException {
+ // nothing to do in init
+ }
+
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ Object apiGwContext = servletRequest.getAttribute(RequestReader.API_GATEWAY_CONTEXT_PROPERTY);
+ if (apiGwContext == null) {
+ log.warn("API Gateway context is null");
+ filterChain.doFilter(servletRequest, servletResponse);
+ return;
+ }
+ if (!AwsProxyRequestContext.class.isAssignableFrom(apiGwContext.getClass())) {
+ log.warn("API Gateway context object is not of valid type");
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ AwsProxyRequestContext ctx = (AwsProxyRequestContext)apiGwContext;
+ if (ctx.getIdentity() == null) {
+ log.warn("Identity context is null");
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+ String cognitoIdentityId = ctx.getIdentity().getCognitoIdentityId();
+ if (cognitoIdentityId == null || "".equals(cognitoIdentityId.trim())) {
+ log.warn("Cognito identity id in request is null");
+ }
+ servletRequest.setAttribute(COGNITO_IDENTITY_ATTRIBUTE, cognitoIdentityId);
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+
+ @Override
+ public void destroy() {
+ // nothing to do in destroy
+ }
+}
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/Error.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/Error.java
new file mode 100644
index 000000000..320f21582
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/Error.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 com.amazonaws.serverless.sample.springboot3.model;
+
+public class Error {
+ private String message;
+
+ public Error(String errorMessage) {
+ message = errorMessage;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/Pet.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/Pet.java
new file mode 100644
index 000000000..4f0c4ba8e
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/Pet.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 com.amazonaws.serverless.sample.springboot3.model;
+
+import java.util.Date;
+
+
+public class Pet {
+ private String id;
+ private String breed;
+ private String name;
+ private Date dateOfBirth;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getBreed() {
+ return breed;
+ }
+
+ public void setBreed(String breed) {
+ this.breed = breed;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Date getDateOfBirth() {
+ return dateOfBirth;
+ }
+
+ public void setDateOfBirth(Date dateOfBirth) {
+ this.dateOfBirth = dateOfBirth;
+ }
+}
diff --git a/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/PetData.java b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/PetData.java
new file mode 100644
index 000000000..68ea3c18b
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/java/com/amazonaws/serverless/sample/springboot3/model/PetData.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"). You may not use this file except in compliance
+ * with the License. A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0/
+ *
+ * or in the "license" file accompanying this file. This file 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 com.amazonaws.serverless.sample.springboot3.model;
+
+
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+
+public class PetData {
+ private static List breeds = new ArrayList<>();
+ static {
+ breeds.add("Afghan Hound");
+ breeds.add("Beagle");
+ breeds.add("Bernese Mountain Dog");
+ breeds.add("Bloodhound");
+ breeds.add("Dalmatian");
+ breeds.add("Jack Russell Terrier");
+ breeds.add("Norwegian Elkhound");
+ }
+
+ private static List names = new ArrayList<>();
+ static {
+ names.add("Bailey");
+ names.add("Bella");
+ names.add("Max");
+ names.add("Lucy");
+ names.add("Charlie");
+ names.add("Molly");
+ names.add("Buddy");
+ names.add("Daisy");
+ names.add("Rocky");
+ names.add("Maggie");
+ names.add("Jake");
+ names.add("Sophie");
+ names.add("Jack");
+ names.add("Sadie");
+ names.add("Toby");
+ names.add("Chloe");
+ names.add("Cody");
+ names.add("Bailey");
+ names.add("Buster");
+ names.add("Lola");
+ names.add("Duke");
+ names.add("Zoe");
+ names.add("Cooper");
+ names.add("Abby");
+ names.add("Riley");
+ names.add("Ginger");
+ names.add("Harley");
+ names.add("Roxy");
+ names.add("Bear");
+ names.add("Gracie");
+ names.add("Tucker");
+ names.add("Coco");
+ names.add("Murphy");
+ names.add("Sasha");
+ names.add("Lucky");
+ names.add("Lily");
+ names.add("Oliver");
+ names.add("Angel");
+ names.add("Sam");
+ names.add("Princess");
+ names.add("Oscar");
+ names.add("Emma");
+ names.add("Teddy");
+ names.add("Annie");
+ names.add("Winston");
+ names.add("Rosie");
+ }
+
+ public static List getBreeds() {
+ return breeds;
+ }
+
+ public static List getNames() {
+ return names;
+ }
+
+ public static String getRandomBreed() {
+ return breeds.get(ThreadLocalRandom.current().nextInt(0, breeds.size() - 1));
+ }
+
+ public static String getRandomName() {
+ return names.get(ThreadLocalRandom.current().nextInt(0, names.size() - 1));
+ }
+
+ public static Date getRandomDoB() {
+ GregorianCalendar gc = new GregorianCalendar();
+
+ int year = ThreadLocalRandom.current().nextInt(
+ Calendar.getInstance().get(Calendar.YEAR) - 15,
+ Calendar.getInstance().get(Calendar.YEAR)
+ );
+
+ gc.set(Calendar.YEAR, year);
+
+ int dayOfYear = ThreadLocalRandom.current().nextInt(1, gc.getActualMaximum(Calendar.DAY_OF_YEAR));
+
+ gc.set(Calendar.DAY_OF_YEAR, dayOfYear);
+ return gc.getTime();
+ }
+}
diff --git a/samples/springboot3/alt-pet-store/src/main/resources/logback.xml b/samples/springboot3/alt-pet-store/src/main/resources/logback.xml
new file mode 100644
index 000000000..14a3a84fa
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/src/main/resources/logback.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/springboot3/alt-pet-store/template.yml b/samples/springboot3/alt-pet-store/template.yml
new file mode 100644
index 000000000..8a51c8d1d
--- /dev/null
+++ b/samples/springboot3/alt-pet-store/template.yml
@@ -0,0 +1,41 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+Description: Example Pet Store API written with spring-cloud-function web-proxy support
+
+Globals:
+ Api:
+ # API Gateway regional endpoints
+ EndpointConfiguration: REGIONAL
+
+Resources:
+ PetStoreFunction:
+ Type: AWS::Serverless::Function
+ Properties:
+# AutoPublishAlias: bcn
+ FunctionName: pet-store-boot-3
+ Handler: com.amazonaws.serverless.proxy.spring.SpringDelegatingLambdaContainerHandler::handleRequest
+ Runtime: java17
+ SnapStart:
+ ApplyOn: PublishedVersions
+ CodeUri: .
+ MemorySize: 1024
+ Policies: AWSLambdaBasicExecutionRole
+ Timeout: 30
+ Environment:
+ Variables:
+ MAIN_CLASS: com.amazonaws.serverless.sample.springboot3.Application
+ Events:
+ HttpApiEvent:
+ Type: HttpApi
+ Properties:
+ TimeoutInMillis: 20000
+ PayloadFormatVersion: '1.0'
+
+Outputs:
+ SpringPetStoreApi:
+ Description: URL for application
+ Value: !Sub 'https://${ServerlessHttpApi}.execute-api.${AWS::Region}.amazonaws.com/pets'
+ Export:
+ Name: SpringPetStoreApi
+
+