Skip to content

Commit 6f54d63

Browse files
committed
add support for Spring Framework 6 AOT engine, which can produce GraalVM native images.
1 parent e8bb3b8 commit 6f54d63

File tree

6 files changed

+139
-46
lines changed

6 files changed

+139
-46
lines changed

pom.xml

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
<maven-plugin-version>1.0.0</maven-plugin-version>
4141
<exec-maven-plugin.version>1.6.0</exec-maven-plugin.version>
4242
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
43-
43+
<reflections.version>0.10.2</reflections.version>
4444
<javax.annotation.version>1.3.2</javax.annotation.version>
4545
<snakeyaml.version>1.33</snakeyaml.version>
4646
<slf4j.version>2.0.3</slf4j.version>
@@ -89,6 +89,11 @@
8989

9090
<dependencyManagement>
9191
<dependencies>
92+
<dependency>
93+
<groupId>org.reflections</groupId>
94+
<artifactId>reflections</artifactId>
95+
<version>${reflections.version}</version>
96+
</dependency>
9297
<dependency>
9398
<groupId>org.apache.commons</groupId>
9499
<artifactId>commons-lang3</artifactId>
@@ -482,49 +487,49 @@
482487
<include>src/test/groovy/**/*.groovy</include>
483488
</includes>
484489

485-
<importOrder> <!-- or a custom ordering -->
486-
<order>java,javax,org,com,com.diffplug,
487-
</order> <!-- or use <file>${basedir}/eclipse.importorder</file> -->
488-
</importOrder>
489-
<greclipse /> <!-- has its own section below -->
490-
<licenseHeader>
491-
<content>
492-
/*
493-
Copyright $YEAR The Kubernetes Authors.
494-
Licensed under the Apache License, Version 2.0 (the "License");
495-
you may not use this file except in compliance with the License.
496-
You may obtain a copy of the License at
497-
http://www.apache.org/licenses/LICENSE-2.0
498-
Unless required by applicable law or agreed to in writing, software
499-
distributed under the License is distributed on an "AS IS" BASIS,
500-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
501-
See the License for the specific language governing permissions and
502-
limitations under the License.
503-
*/
504-
</content>
505-
</licenseHeader>
506-
</groovy>
507-
<licenseHeader>
508-
<content>
509-
/*
510-
Copyright $YEAR The Kubernetes Authors.
511-
Licensed under the Apache License, Version 2.0 (the "License");
512-
you may not use this file except in compliance with the License.
513-
You may obtain a copy of the License at
514-
http://www.apache.org/licenses/LICENSE-2.0
515-
Unless required by applicable law or agreed to in writing, software
516-
distributed under the License is distributed on an "AS IS" BASIS,
517-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
518-
See the License for the specific language governing permissions and
519-
limitations under the License.
520-
*/
521-
</content>
522-
<delimiter>package </delimiter>
523-
</licenseHeader>
524-
</configuration>
525-
</plugin>
526-
</plugins>
527-
</build>
490+
<importOrder> <!-- or a custom ordering -->
491+
<order>java,javax,org,com,com.diffplug,
492+
</order> <!-- or use <file>${basedir}/eclipse.importorder</file> -->
493+
</importOrder>
494+
<greclipse/> <!-- has its own section below -->
495+
<licenseHeader>
496+
<content>
497+
/*
498+
Copyright $YEAR The Kubernetes Authors.
499+
Licensed under the Apache License, Version 2.0 (the "License");
500+
you may not use this file except in compliance with the License.
501+
You may obtain a copy of the License at
502+
http://www.apache.org/licenses/LICENSE-2.0
503+
Unless required by applicable law or agreed to in writing, software
504+
distributed under the License is distributed on an "AS IS" BASIS,
505+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
506+
See the License for the specific language governing permissions and
507+
limitations under the License.
508+
*/
509+
</content>
510+
</licenseHeader>
511+
</groovy>
512+
<licenseHeader>
513+
<content>
514+
/*
515+
Copyright $YEAR The Kubernetes Authors.
516+
Licensed under the Apache License, Version 2.0 (the "License");
517+
you may not use this file except in compliance with the License.
518+
You may obtain a copy of the License at
519+
http://www.apache.org/licenses/LICENSE-2.0
520+
Unless required by applicable law or agreed to in writing, software
521+
distributed under the License is distributed on an "AS IS" BASIS,
522+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
523+
See the License for the specific language governing permissions and
524+
limitations under the License.
525+
*/
526+
</content>
527+
<delimiter>package</delimiter>
528+
</licenseHeader>
529+
</configuration>
530+
</plugin>
531+
</plugins>
532+
</build>
528533

529534
<profiles>
530535
<profile>

spring/pom.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
<relativePath>../pom.xml</relativePath>
1515
</parent>
1616

17-
1817
<dependencies>
18+
<dependency>
19+
<groupId>org.reflections</groupId>
20+
<artifactId>reflections</artifactId>
21+
</dependency>
1922
<dependency>
2023
<groupId>io.kubernetes</groupId>
2124
<artifactId>client-java-api</artifactId>

spring/src/main/java/io/kubernetes/client/spring/extended/controller/config/KubernetesReconcilerAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import org.springframework.context.annotation.Bean;
1818
import org.springframework.context.annotation.Configuration;
1919

20-
@Configuration(proxyBeanMethods = false)
20+
@Configuration
2121
@ConditionalOnKubernetesReconcilerEnabled
2222
public class KubernetesReconcilerAutoConfiguration {
2323

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package io.kubernetes.client.spring.extended.controller.config.aot;
2+
3+
4+
import com.google.gson.annotations.JsonAdapter;
5+
import io.swagger.annotations.ApiModel;
6+
import org.jetbrains.annotations.NotNull;
7+
import org.reflections.Reflections;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
import org.springframework.aot.hint.MemberCategory;
11+
import org.springframework.aot.hint.RuntimeHints;
12+
import org.springframework.aot.hint.TypeReference;
13+
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution;
14+
import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor;
15+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
16+
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
17+
18+
import java.lang.annotation.Annotation;
19+
import java.util.Collection;
20+
import java.util.HashSet;
21+
import java.util.Set;
22+
23+
/**
24+
* Registers hints to support Spring Framework 6 and Spring Boot 3 AOT
25+
*/
26+
public class KubernetesBeanFactoryInitializationAotProcessor implements BeanFactoryInitializationAotProcessor {
27+
28+
private static final Logger LOGGER = LoggerFactory.getLogger(KubernetesBeanFactoryInitializationAotProcessor.class);
29+
30+
private final MemberCategory[] allMemberCategories = MemberCategory.values();
31+
32+
@Override
33+
public BeanFactoryInitializationAotContribution processAheadOfTime(
34+
@NotNull ConfigurableListableBeanFactory beanFactory) {
35+
return (generationContext, beanFactoryInitializationCode) -> {
36+
RuntimeHints hints = generationContext.getRuntimeHints();
37+
String[] classNames = new String[]{
38+
"com.google.gson.JsonElement",//
39+
"io.kubernetes.client.informer.cache.ProcessorListener", //
40+
"io.kubernetes.client.extended.controller.Controller", //
41+
"io.kubernetes.client.util.generic.GenericKubernetesApi$StatusPatch", //
42+
"io.kubernetes.client.util.Watch$Response" //
43+
};
44+
for (String className : classNames) {
45+
LOGGER.info("registering " + className + " for reflection");
46+
hints.reflection().registerType(TypeReference.of(className), allMemberCategories);
47+
}
48+
registerForPackage("io.kubernetes", hints);
49+
Collection<String> packages = AutoConfigurationPackages.get(beanFactory);
50+
for (String packageName : packages) {
51+
registerForPackage(packageName, hints);
52+
}
53+
};
54+
}
55+
56+
private void registerForPackage(String packageName, RuntimeHints hints) {
57+
Reflections reflections = new Reflections(packageName);
58+
Set<Class<?>> apiModels = reflections.getTypesAnnotatedWith(ApiModel.class);
59+
Set<Class<?>> jsonAdapters = findJsonAdapters(reflections);
60+
Set<Class<?>> all = new HashSet<>();
61+
all.addAll(jsonAdapters);
62+
all.addAll(apiModels);
63+
for (Class<?> clazz : all) {
64+
LOGGER.info("registering " + clazz.getName() + " for reflection");
65+
hints.reflection().registerType(clazz, allMemberCategories);
66+
}
67+
}
68+
69+
private <R extends Annotation> Set<Class<?>> findJsonAdapters(Reflections reflections) {
70+
Class<JsonAdapter> jsonAdapterClass = JsonAdapter.class;
71+
Set<Class<?>> classes = new HashSet<>();
72+
for (Class<?> clazz : reflections.getTypesAnnotatedWith(jsonAdapterClass)) {
73+
JsonAdapter annotation = clazz.getAnnotation(jsonAdapterClass);
74+
if (null != annotation) {
75+
classes.add(annotation.value());
76+
}
77+
classes.add(clazz);
78+
}
79+
return classes;
80+
}
81+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor=io.kubernetes.client.spring.extended.controller.config.aot.KubernetesBeanFactoryInitializationAotProcessor
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
io.kubernetes.client.spring.extended.controller.config.KubernetesInformerAutoConfiguration
2+
io.kubernetes.client.spring.extended.controller.config.KubernetesReconcilerAutoConfiguration
3+
io.kubernetes.client.spring.extended.manifests.config.KubernetesManifestsAutoConfiguration

0 commit comments

Comments
 (0)