Skip to content

Commit 569ee00

Browse files
authored
Merge pull request #1585 from tobixlea/sjc-spring-boot-update
Add Spring Boot 4.0 support with working samples
2 parents b1e4b37 + 012c924 commit 569ee00

File tree

149 files changed

+7631
-143
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+7631
-143
lines changed

.github/workflows/continuous-integration-workflow.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@ jobs:
8585
- name: Build with Spring Boot 3.3.x
8686
run: ./gha_build.sh springboot3 false false -Dspringboot.version=3.3.6 -Dspring.version=6.1.15 -Dspringsecurity.version=6.3.5 -Ddependency-check.skip=true
8787

88+
build_springboot4:
89+
name: Build and test SpringBoot 4
90+
runs-on: ubuntu-latest
91+
steps:
92+
- uses: actions/checkout@v3
93+
- name: Set up JDK 17
94+
uses: actions/setup-java@v3
95+
with:
96+
distribution: 'corretto'
97+
java-version: 17
98+
- name: Build latest
99+
run: ./gha_build.sh springboot4 true true
88100
# temporarily disabled as Struts is not released at the moment
89101
# build_struts2:
90102
# name: Build and test Struts

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Currently the following versions are maintained:
88
| Version | Branch | Java Enterprise support | Spring versions | JAX-RS/ Jersey version | Struts support | Spark support |
99
|---------|--------|-----------------------------|-----------------|------------------------|----------------|---------------|
1010
| 1.x | [1.x](https://github.com/aws/serverless-java-container/tree/1.x) | Java EE (javax.*) | 5.x (Boot 2.x) | 2.x | :white_check_mark: | :white_check_mark: |
11-
| 2.x | [main](https://github.com/aws/serverless-java-container/tree/main) | Jakarta EE 9-10 (jakarta.*) | 6.x (Boot 3.x) | 3.x | :x: | :x: |
12-
| 3.x | | Jakarta EE 11 (jakarta.*) | 7.x (Boot 4.x) | 4.x | :x: | :x: |
11+
| 2.x | [2.1.x](https://github.com/aws/serverless-java-container/tree/2.1.x) | Jakarta EE 9-10 (jakarta.*) | 6.x (Boot 3.x) | 3.x | :x: | :x: |
12+
| 3.x | [main](https://github.com/aws/serverless-java-container/tree/main) | Jakarta EE 11 (jakarta.*) | 7.x (Boot 4.x) | 3.x | :x: | :x: |
1313

1414
Follow the quick start guides in [our wiki](https://github.com/aws/serverless-java-container/wiki) to integrate Serverless Java Container with your project:
1515
* [Spring quick start](https://github.com/aws/serverless-java-container/wiki/Quick-start---Spring)

aws-serverless-java-container-core/pom.xml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,19 @@
66
<name>AWS Serverless Java container support - Core</name>
77
<description>Allows Java applications written for a servlet container to run in AWS Lambda</description>
88
<url>https://aws.amazon.com/lambda</url>
9-
<version>2.1.5-SNAPSHOT</version>
9+
<version>3.0.0-SNAPSHOT</version>
1010

1111
<parent>
1212
<groupId>com.amazonaws.serverless</groupId>
1313
<artifactId>aws-serverless-java-container</artifactId>
14-
<version>2.1.5-SNAPSHOT</version>
14+
<version>3.0.0-SNAPSHOT</version>
1515
<relativePath>..</relativePath>
1616
</parent>
1717

1818
<properties>
1919
<jaxrs.version>3.1.0</jaxrs.version>
20-
<servlet.version>6.0.0</servlet.version>
20+
<servlet.version>6.1.0</servlet.version>
21+
<jackson.version>3.0.2</jackson.version>
2122
</properties>
2223

2324
<dependencies>
@@ -40,13 +41,13 @@
4041
</dependency>
4142

4243
<dependency>
43-
<groupId>com.fasterxml.jackson.core</groupId>
44+
<groupId>tools.jackson.core</groupId>
4445
<artifactId>jackson-databind</artifactId>
4546
<version>${jackson.version}</version>
4647
</dependency>
4748

4849
<dependency>
49-
<groupId>com.fasterxml.jackson.module</groupId>
50+
<groupId>tools.jackson.module</groupId>
5051
<artifactId>jackson-module-afterburner</artifactId>
5152
<version>${jackson.version}</version>
5253
</dependency>

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/AwsProxyExceptionHandler.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import com.amazonaws.serverless.proxy.model.ErrorModel;
1919
import com.amazonaws.serverless.proxy.model.Headers;
2020

21-
import com.fasterxml.jackson.core.JsonProcessingException;
21+
import tools.jackson.core.JacksonException;
2222
import jakarta.ws.rs.core.Response;
2323
import org.slf4j.Logger;
2424
import org.slf4j.LoggerFactory;
@@ -103,7 +103,7 @@ protected String getErrorJson(String message) {
103103

104104
try {
105105
return LambdaContainerHandler.getObjectMapper().writeValueAsString(new ErrorModel(message));
106-
} catch (JsonProcessingException e) {
106+
} catch (JacksonException e) {
107107
log.error("Could not produce error JSON", e);
108108
return "{ \"message\": \"" + message + "\" }";
109109
}

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/LambdaContainerHandler.java

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@
1919
import com.amazonaws.serverless.proxy.model.ContainerConfig;
2020
import com.amazonaws.services.lambda.runtime.Context;
2121

22-
import com.fasterxml.jackson.core.JsonParseException;
23-
import com.fasterxml.jackson.databind.JsonMappingException;
24-
import com.fasterxml.jackson.databind.ObjectMapper;
25-
import com.fasterxml.jackson.databind.ObjectReader;
26-
import com.fasterxml.jackson.databind.ObjectWriter;
27-
import com.fasterxml.jackson.module.afterburner.AfterburnerModule;
22+
import tools.jackson.core.JacksonException;
23+
import tools.jackson.databind.ObjectMapper;
24+
import tools.jackson.databind.ObjectReader;
25+
import tools.jackson.databind.ObjectWriter;
2826
import org.slf4j.Logger;
2927
import org.slf4j.LoggerFactory;
3028

@@ -86,10 +84,9 @@ public abstract class LambdaContainerHandler<RequestType, ResponseType, Containe
8684
}
8785

8886
private static void registerAfterBurner() {
89-
objectMapper.registerModule(new AfterburnerModule());
87+
// AfterburnerModule is built-in in Jackson 3, no need to register
9088
}
9189

92-
9390
//-------------------------------------------------------------
9491
// Constructors
9592
//-------------------------------------------------------------
@@ -258,12 +255,9 @@ public void proxyStream(InputStream input, OutputStream output, Context context)
258255
ResponseType resp = proxy(request, context);
259256

260257
objectWriter.writeValue(output, resp);
261-
} catch (JsonParseException e) {
258+
} catch (JacksonException e) {
262259
log.error("Error while parsing request object stream", e);
263260
getObjectMapper().writeValue(output, exceptionHandler.handle(e));
264-
} catch (JsonMappingException e) {
265-
log.error("Error while mapping object to RequestType class", e);
266-
getObjectMapper().writeValue(output, exceptionHandler.handle(e));
267261
} finally {
268262
output.flush();
269263
output.close();

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/jaxrs/AwsHttpApiV2SecurityContext.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import com.amazonaws.serverless.proxy.internal.SecurityUtils;
1717
import com.amazonaws.serverless.proxy.model.HttpApiV2ProxyRequest;
1818
import com.amazonaws.services.lambda.runtime.Context;
19-
import com.fasterxml.jackson.core.JsonProcessingException;
20-
import com.fasterxml.jackson.databind.JsonNode;
19+
import tools.jackson.core.JacksonException;
20+
import tools.jackson.databind.JsonNode;
2121
import org.slf4j.Logger;
2222
import org.slf4j.LoggerFactory;
2323

@@ -66,7 +66,7 @@ public Principal getUserPrincipal() {
6666
return (() -> {
6767
return subject;
6868
});
69-
} catch (JsonProcessingException e) {
69+
} catch (JacksonException e) {
7070
log.error("Error while attempting to parse JWT body for requestId: " + SecurityUtils.crlf(event.getRequestContext().getRequestId()), e);
7171
return null;
7272
}

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsHttpServletResponse.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import jakarta.servlet.http.HttpServletRequest;
2929
import jakarta.servlet.http.HttpServletResponse;
3030
import jakarta.ws.rs.core.HttpHeaders;
31+
import java.nio.ByteBuffer;
3132
import jakarta.ws.rs.core.MediaType;
3233
import java.io.ByteArrayOutputStream;
3334
import java.io.IOException;
@@ -150,6 +151,16 @@ public void sendRedirect(String s) throws IOException {
150151
flushBuffer();
151152
}
152153

154+
@Override
155+
public void sendRedirect(String location, int sc, boolean clearBuffer) throws IOException {
156+
setStatus(sc);
157+
addHeader(HttpHeaders.LOCATION, location);
158+
if (clearBuffer) {
159+
resetBuffer();
160+
}
161+
flushBuffer();
162+
}
163+
153164

154165
@Override
155166
public void setDateHeader(String s, long l) {
@@ -297,6 +308,25 @@ public void write(int b) throws IOException {
297308
}
298309
}
299310

311+
@Override
312+
public void write(ByteBuffer b) throws IOException {
313+
try {
314+
if (b.hasArray()) {
315+
bodyOutputStream.write(b.array(), b.arrayOffset() + b.position(), b.remaining());
316+
b.position(b.limit());
317+
} else {
318+
byte[] buf = new byte[b.remaining()];
319+
b.get(buf);
320+
bodyOutputStream.write(buf);
321+
}
322+
} catch (Exception e) {
323+
log.error("Cannot write to output stream", e);
324+
if (listener != null) {
325+
listener.onError(e);
326+
}
327+
}
328+
}
329+
300330
@Override
301331
public void flush() throws IOException {
302332
flushBuffer();

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsProxyHttpServletRequest.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -607,12 +607,22 @@ private List<String> getHeaderValues(String key) {
607607

608608
if (request.getRequestSource() == RequestSource.API_GATEWAY) {
609609
if ("referer".equals(key.toLowerCase(Locale.ENGLISH))) {
610-
values.add(request.getRequestContext().getIdentity().getCaller());
611-
return values;
610+
if (request.getRequestContext() != null && request.getRequestContext().getIdentity() != null) {
611+
String caller = request.getRequestContext().getIdentity().getCaller();
612+
if (caller != null) {
613+
values.add(caller);
614+
return values;
615+
}
616+
}
612617
}
613618
if ("user-agent".equals(key.toLowerCase(Locale.ENGLISH))) {
614-
values.add(request.getRequestContext().getIdentity().getUserAgent());
615-
return values;
619+
if (request.getRequestContext() != null && request.getRequestContext().getIdentity() != null) {
620+
String userAgent = request.getRequestContext().getIdentity().getUserAgent();
621+
if (userAgent != null) {
622+
values.add(userAgent);
623+
return values;
624+
}
625+
}
616626
}
617627
}
618628

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/internal/servlet/AwsServletInputStream.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import jakarta.servlet.ServletInputStream;
2121
import java.io.IOException;
2222
import java.io.InputStream;
23+
import java.nio.ByteBuffer;
2324

2425
public class AwsServletInputStream extends ServletInputStream {
2526
private static Logger log = LoggerFactory.getLogger(AwsServletInputStream.class);
@@ -73,4 +74,23 @@ public int read()
7374
}
7475
return readByte;
7576
}
77+
78+
@Override
79+
public int read(ByteBuffer b) throws IOException {
80+
if (bodyStream == null || bodyStream instanceof NullInputStream) {
81+
return -1;
82+
}
83+
if (!b.hasRemaining()) {
84+
return 0;
85+
}
86+
byte[] buf = new byte[b.remaining()];
87+
int bytesRead = bodyStream.read(buf);
88+
if (bytesRead > 0) {
89+
b.put(buf, 0, bytesRead);
90+
}
91+
if (bytesRead == -1) {
92+
finished = true;
93+
}
94+
return bytesRead;
95+
}
7696
}

aws-serverless-java-container-core/src/main/java/com/amazonaws/serverless/proxy/model/HttpApiV2AuthorizerMap.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,16 @@
1313
package com.amazonaws.serverless.proxy.model;
1414

1515
import com.amazonaws.serverless.proxy.internal.LambdaContainerHandler;
16-
import com.fasterxml.jackson.core.JsonGenerator;
17-
import com.fasterxml.jackson.core.JsonParser;
18-
import com.fasterxml.jackson.core.JsonProcessingException;
19-
import com.fasterxml.jackson.databind.DeserializationContext;
20-
import com.fasterxml.jackson.databind.JsonNode;
21-
import com.fasterxml.jackson.databind.SerializerProvider;
22-
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
23-
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
24-
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
25-
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
26-
import com.fasterxml.jackson.databind.type.TypeFactory;
16+
import tools.jackson.core.JsonGenerator;
17+
import tools.jackson.core.JsonParser;
18+
import tools.jackson.databind.DeserializationContext;
19+
import tools.jackson.databind.JsonNode;
20+
import tools.jackson.databind.SerializationContext;
21+
import tools.jackson.databind.annotation.JsonDeserialize;
22+
import tools.jackson.databind.annotation.JsonSerialize;
23+
import tools.jackson.databind.deser.std.StdDeserializer;
24+
import tools.jackson.databind.ser.std.StdSerializer;
25+
import tools.jackson.databind.type.TypeFactory;
2726

2827
import java.io.IOException;
2928
import java.util.HashMap;
@@ -77,18 +76,17 @@ public HttpApiV2AuthorizerDeserializer() {
7776
}
7877

7978
@Override
80-
public HttpApiV2AuthorizerMap deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
81-
throws IOException, JsonProcessingException {
79+
public HttpApiV2AuthorizerMap deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) {
8280
HttpApiV2AuthorizerMap map = new HttpApiV2AuthorizerMap();
83-
JsonNode node = jsonParser.getCodec().readTree(jsonParser);
81+
JsonNode node = deserializationContext.readTree(jsonParser);
8482
if (node.has(JWT_KEY)) {
8583
HttpApiV2JwtAuthorizer authorizer = LambdaContainerHandler.getObjectMapper()
8684
.treeToValue(node.get(JWT_KEY), HttpApiV2JwtAuthorizer.class);
8785
map.putJwtAuthorizer(authorizer);
8886
}
8987
if (node.has(LAMBDA_KEY)) {
9088
Map<String, Object> context = LambdaContainerHandler.getObjectMapper().treeToValue(node.get(LAMBDA_KEY),
91-
TypeFactory.defaultInstance().constructMapType(HashMap.class, String.class, Object.class));
89+
LambdaContainerHandler.getObjectMapper().getTypeFactory().constructMapType(HashMap.class, String.class, Object.class));
9290
map.put(LAMBDA_KEY, context);
9391
}
9492
if (node.has(IAM_KEY)) {
@@ -110,16 +108,19 @@ public HttpApiV2AuthorizerSerializer() {
110108

111109
@Override
112110
public void serialize(HttpApiV2AuthorizerMap httpApiV2AuthorizerMap, JsonGenerator jsonGenerator,
113-
SerializerProvider serializerProvider) throws IOException {
111+
SerializationContext serializationContext) {
114112
jsonGenerator.writeStartObject();
115113
if (httpApiV2AuthorizerMap.isJwt()) {
116-
jsonGenerator.writeObjectField(JWT_KEY, httpApiV2AuthorizerMap.getJwtAuthorizer());
114+
jsonGenerator.writeName(JWT_KEY);
115+
jsonGenerator.writePOJO(httpApiV2AuthorizerMap.getJwtAuthorizer());
117116
}
118117
if (httpApiV2AuthorizerMap.isLambda()) {
119-
jsonGenerator.writeObjectField(LAMBDA_KEY, httpApiV2AuthorizerMap.getLambdaAuthorizerContext());
118+
jsonGenerator.writeName(LAMBDA_KEY);
119+
jsonGenerator.writePOJO(httpApiV2AuthorizerMap.getLambdaAuthorizerContext());
120120
}
121121
if (httpApiV2AuthorizerMap.isIam()) {
122-
jsonGenerator.writeObjectField(IAM_KEY, httpApiV2AuthorizerMap.get(IAM_KEY));
122+
jsonGenerator.writeName(IAM_KEY);
123+
jsonGenerator.writePOJO(httpApiV2AuthorizerMap.get(IAM_KEY));
123124
}
124125
jsonGenerator.writeEndObject();
125126
}

0 commit comments

Comments
 (0)