Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce native support for config stores, core, SQS and SNS module #856

Merged
merged 22 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
39907a9
First hint
MatejNedic Apr 15, 2023
1e80a11
Introduce native hints for Core and Config modules
MatejNedic Jul 28, 2023
a79b9b5
Merge branch 'awspring:main' into introduce-native-support
MatejNedic Aug 1, 2023
1234081
Introduce Native hint so SQSListener has Reflection hints when intros…
MatejNedic Aug 2, 2023
8f35ccd
Introduce Native hint for SNS integration
MatejNedic Aug 4, 2023
2b1a83e
Introduce ListenerReflectiveProcessor to SqsListener
MatejNedic Aug 4, 2023
ec900a0
Introduce ListenerReflectiveProcessor to SqsListener
MatejNedic Aug 4, 2023
f4af76e
Start working on S3 native hints
MatejNedic Aug 4, 2023
b052743
Introduce reflection of Sts class
MatejNedic Aug 13, 2023
7dd2e42
Introduce MessageMapping annotation
MatejNedic Nov 25, 2023
969a6e0
Rename to Spring standard
MatejNedic Dec 11, 2023
5b86502
Merge branch 'main' into introduce-native-support
MatejNedic Jun 17, 2024
8e3792e
Make CRT client Native Compatible
MatejNedic Jun 17, 2024
a3e4280
Make adjustment
MatejNedic Jun 17, 2024
0b212d9
Merge branch 'main' into introduce-native-support
MatejNedic Jun 17, 2024
7770a95
Update so CRT client hints are registered
MatejNedic Jun 17, 2024
b8d6e50
add new hints
MatejNedic Sep 19, 2024
12ed437
Merge branch 'main' into introduce-native-support
MatejNedic Dec 8, 2024
b8206fd
Introduce Native section in Core docs
MatejNedic Dec 8, 2024
2c51b90
Merge remote-tracking branch 'origin/main' into introduce-native-support
maciejwalkowiak Dec 9, 2024
0785e92
Update docs
maciejwalkowiak Dec 9, 2024
98f0079
Formatting
maciejwalkowiak Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/src/main/asciidoc/core.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -260,3 +260,12 @@ There can be multiple customizer beans present in single application context and

Client-specific customizations can be applied through client-specific customizer interfaces (for example `S3ClientCustomizer` for S3). See integrations documentation for details.


=== GraalVM Native Image

Since version 3.3.0 the framework provides **experimental** support for GraalVM Native Image build.

Known issues are:

- in DynamoDB integration, `StaticTableSchema` must be used instead of `DynamicTableSchema` (see https://github.com/aws/aws-sdk-java-v2/issues/2445)
- in S3 integration, when working with CRT client, following guide must be followed: https://github.com/awslabs/aws-crt-java?tab=readme-ov-file#graalvm-support
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Copyright 2013-2023 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
*
* https://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 io.awspring.cloud.autoconfigure.config;

import io.awspring.cloud.autoconfigure.config.parameterstore.ParameterStorePropertySources;
import io.awspring.cloud.autoconfigure.config.secretsmanager.SecretsManagerPropertySources;
import io.awspring.cloud.parameterstore.ParameterStorePropertySource;
import io.awspring.cloud.secretsmanager.SecretsManagerPropertySource;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.util.ClassUtils;

public class ConfigStoreRuntimeHints implements RuntimeHintsRegistrar {

@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (ClassUtils.isPresent("io.awspring.cloud.parameterstore.ParameterStorePropertySource", classLoader)) {
hints.reflection().registerType(TypeReference.of(ParameterStorePropertySources.class),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));
hints.reflection().registerType(TypeReference.of(ParameterStorePropertySource.class),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));
}

if (ClassUtils.isPresent("io.awspring.cloud.secretsmanager.SecretsManagerPropertySource", classLoader)) {
hints.reflection().registerType(TypeReference.of(SecretsManagerPropertySources.class),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));

hints.reflection().registerType(TypeReference.of(SecretsManagerPropertySource.class),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2013-2023 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
*
* https://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 io.awspring.cloud.autoconfigure.core;

import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;
import org.springframework.util.ClassUtils;

public class CoreAOT implements RuntimeHintsRegistrar {

private static final String STS_WEB_IDENTITY_TOKEN_FILE_CREDENTIALS_PROVIDER = "software.amazon.awssdk.services.sts.auth.StsWebIdentityTokenFileCredentialsProvider";

@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
if (ClassUtils.isPresent(STS_WEB_IDENTITY_TOKEN_FILE_CREDENTIALS_PROVIDER, classLoader)) {
hints.reflection().registerType(TypeReference.of(STS_WEB_IDENTITY_TOKEN_FILE_CREDENTIALS_PROVIDER),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
io.awspring.cloud.autoconfigure.config.ConfigStoreRuntimeHints,\
io.awspring.cloud.autoconfigure.core.CoreAOT
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Copyright 2013-2023 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
*
* https://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 io.awspring.cloud.core;

import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;

public class AWSCoreRuntimeHints implements RuntimeHintsRegistrar {

@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerPattern("io/awspring/cloud/core/SpringCloudClientConfiguration.properties");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,4 @@ public ClientOverrideConfiguration clientOverrideConfiguration() {
private String getUserAgent() {
return NAME + "/" + version;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
io.awspring.cloud.core.AWSCoreRuntimeHints
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.springframework.modulith.events.ApplicationModuleListener;
import org.springframework.modulith.events.Externalized;
import org.springframework.test.context.DynamicPropertyRegistrar;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.transaction.annotation.Transactional;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.utility.DockerImageName;
Expand Down Expand Up @@ -64,6 +63,7 @@ DynamicPropertyRegistrar dynamicPropertyRegistrar(LocalStackContainer localstack
registry.add("spring.cloud.aws.region.static", localstack::getRegion);
};
}

@Bean
LocalStackContainer localStackContainer() {
return new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.8.1"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import org.springframework.modulith.events.ApplicationModuleListener;
import org.springframework.modulith.events.Externalized;
import org.springframework.test.context.DynamicPropertyRegistrar;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.transaction.annotation.Transactional;
import org.testcontainers.containers.localstack.LocalStackContainer;
import org.testcontainers.utility.DockerImageName;
Expand Down Expand Up @@ -62,6 +61,7 @@ DynamicPropertyRegistrar dynamicPropertyRegistrar(LocalStackContainer localstack
registry.add("spring.cloud.aws.region.static", localstack::getRegion);
};
}

@Bean
LocalStackContainer localStackContainer() {
return new LocalStackContainer(DockerImageName.parse("localstack/localstack:3.8.1"));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
io.awspring.cloud.s3.S3RuntimeHints
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright 2013-2023 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
*
* https://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 io.awspring.cloud.s3;

import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;

public class S3RuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.resources().registerPattern("io/awspring/cloud/s3/S3ObjectContentTypeResolver.properties");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2013-2023 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
*
* https://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 io.awspring.cloud.sns;

import io.awspring.cloud.sns.handlers.NotificationMessageHandlerMethodArgumentResolver;
import io.awspring.cloud.sns.handlers.NotificationStatus;
import io.awspring.cloud.sns.handlers.NotificationStatusHandlerMethodArgumentResolver;
import io.awspring.cloud.sns.handlers.NotificationSubjectHandlerMethodArgumentResolver;
import java.util.stream.Stream;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.TypeReference;

public class SnsRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
Stream.of(NotificationStatusHandlerMethodArgumentResolver.class,
NotificationStatusHandlerMethodArgumentResolver.AmazonSnsNotificationStatus.class,
NotificationMessageHandlerMethodArgumentResolver.class,
NotificationMessageHandlerMethodArgumentResolver.ByteArrayHttpInputMessage.class,
NotificationSubjectHandlerMethodArgumentResolver.class, NotificationStatus.class)
.forEach(type -> hints.reflection().registerType(TypeReference.of(type),
hint -> hint.withMembers(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
MemberCategory.INTROSPECT_DECLARED_METHODS, MemberCategory.DECLARED_FIELDS)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import io.awspring.cloud.sns.annotation.handlers.NotificationSubject;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.core.annotation.AliasFor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -44,6 +45,7 @@
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(headers = "x-amz-sns-message-type=Notification", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
@Reflective(processors = SnsControllerMappingReflectiveProcessor.class)
public @interface NotificationMessageMapping {

@AliasFor(annotation = RequestMapping.class, attribute = "path")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.core.annotation.AliasFor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -42,6 +43,7 @@
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(headers = "x-amz-sns-message-type=SubscriptionConfirmation", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
@Reflective(processors = SnsControllerMappingReflectiveProcessor.class)
public @interface NotificationSubscriptionMapping {

@AliasFor(annotation = RequestMapping.class, attribute = "path")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.core.annotation.AliasFor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -43,6 +44,7 @@
@Retention(RetentionPolicy.RUNTIME)
@RequestMapping(headers = "x-amz-sns-message-type=UnsubscribeConfirmation", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.NO_CONTENT)
@Reflective(processors = SnsControllerMappingReflectiveProcessor.class)
public @interface NotificationUnsubscribeConfirmationMapping {

@AliasFor(annotation = RequestMapping.class, attribute = "path")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* Copyright 2013-2023 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
*
* https://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 io.awspring.cloud.sns.annotation.endpoint;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.ExecutableMode;
import org.springframework.aot.hint.ReflectionHints;
import org.springframework.aot.hint.annotation.ReflectiveProcessor;
import org.springframework.core.MethodParameter;

/**
* Heavily inspired by Spring Frameworks ControllerMappingReflectiveProcessor.
*
* @author Matej Nedic
* @author Stephane Nicoll
* @author Sebastien Deleuze
* @since 3.0.2
*/
public class SnsControllerMappingReflectiveProcessor implements ReflectiveProcessor {
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();

@Override
public void registerReflectionHints(ReflectionHints hints, AnnotatedElement element) {
if (element instanceof Class<?> type) {
registerTypeHints(hints, type);
}
else if (element instanceof Method method) {
registerMethodHints(hints, method);
}
}

protected void registerTypeHints(ReflectionHints hints, Class<?> type) {
hints.registerType(type);
}

protected void registerMethodHints(ReflectionHints hints, Method method) {
hints.registerMethod(method, ExecutableMode.INVOKE);
for (Parameter parameter : method.getParameters()) {
registerParameterTypeHints(hints, MethodParameter.forParameter(parameter));
}
registerReturnTypeHints(hints, MethodParameter.forExecutable(method, -1));
}

protected void registerParameterTypeHints(ReflectionHints hints, MethodParameter methodParameter) {
this.bindingRegistrar.registerReflectionHints(hints, methodParameter.getGenericParameterType());
}

protected void registerReturnTypeHints(ReflectionHints hints, MethodParameter returnTypeParameter) {
this.bindingRegistrar.registerReflectionHints(hints, getEntityType(returnTypeParameter));
}

private Type getEntityType(MethodParameter parameter) {
MethodParameter nestedParameter = parameter.nested();
return (nestedParameter.getNestedParameterType() == nestedParameter.getParameterType() ? null
: nestedParameter.getNestedParameterType());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ protected Object doResolveArgumentFromNotificationMessage(JsonNode content, Http
"Error converting notification message with payload:" + messageContent, request);
}

private static final class ByteArrayHttpInputMessage implements HttpInputMessage {
public static final class ByteArrayHttpInputMessage implements HttpInputMessage {

private final String content;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ protected Object doResolveArgumentFromNotificationMessage(JsonNode content, Http
content.get("Token").asText());
}

private static final class AmazonSnsNotificationStatus implements NotificationStatus {
public static final class AmazonSnsNotificationStatus implements NotificationStatus {

private final SnsClient snsClient;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
org.springframework.aot.hint.RuntimeHintsRegistrar=\
io.awspring.cloud.sns.SnsRuntimeHints
Loading
Loading