Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 7e9315a

Browse files
committed
Provide implementation of BeanFactoryNativeConfigurationProcessor for function types
Add initial implementation of FunctionTypeProcessor and FunctionTypeProcessorTests Modified samples to remove TypeHint as well as reference to it in the README Upgrade Spring Cloud dependency to 2021.0.0
1 parent 882297a commit 7e9315a

File tree

8 files changed

+202
-9
lines changed

8 files changed

+202
-9
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<graalvm.version>21.3.0</graalvm.version>
1616
<docs.resources.version>0.2.1.RELEASE</docs.resources.version>
1717
<spring.boot.version>2.6.1</spring.boot.version>
18-
<spring.cloud.version>2021.0.0-RC1</spring.cloud.version>
18+
<spring.cloud.version>2021.0.0</spring.cloud.version>
1919
<spring.security.authorization-server.version>0.1.0</spring.security.authorization-server.version>
2020
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
2121
<java.version>11</java.version>

samples/cloud-function-aws/README.md

-2
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ $> ./build.sh
2626
2727
```
2828

29-
>>NOTE: You will notice we apply `@TypeHint(types = {Person.class}` (see `DemoApplication`). Given that JSON converter will apply reflection to serialize/de-serialize `Person` type for the function input we need to provide minimal reflection configuration and `@TypeHint` will let us do just that.
30-
3129
### Deploy and test
3230

3331
- Navigate to AWS Lambda dashboard and create a new function (name it anyway you want).

samples/cloud-function-aws/src/main/java/com/example/demo/DemoApplication.java

-5
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@
22

33
import org.springframework.boot.SpringApplication;
44
import org.springframework.boot.autoconfigure.SpringBootApplication;
5-
import org.springframework.nativex.hint.TypeHint;
65

7-
import com.example.demo.domain.Person;
8-
9-
@TypeHint(types = {Person.class})
106
@SpringBootApplication
117
public class DemoApplication {
128

139
public static void main(String[] args) {
1410
SpringApplication.run(DemoApplication.class, args);
1511
}
16-
1712
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

spring-aot/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,11 @@
9090
<artifactId>kafka-avro-serializer</artifactId>
9191
<optional>true</optional>
9292
</dependency>
93+
<dependency>
94+
<groupId>org.springframework.cloud</groupId>
95+
<artifactId>spring-cloud-function-context</artifactId>
96+
<optional>true</optional>
97+
</dependency>
9398

9499
<dependency>
95100
<groupId>com.google.code.findbugs</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2021-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.function;
18+
19+
import java.lang.reflect.Type;
20+
import java.util.HashSet;
21+
import java.util.Set;
22+
import java.util.function.Consumer;
23+
import java.util.function.Function;
24+
25+
import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.BeanFactoryNativeConfigurationProcessor;
26+
import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
27+
import org.springframework.aot.support.BeanFactoryProcessor;
28+
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
29+
import org.springframework.cloud.function.context.catalog.FunctionTypeUtils;
30+
import org.springframework.nativex.hint.TypeAccess;
31+
32+
/**
33+
* Ensures that Function/Consumer input types declared b the user are reflectively available.
34+
*
35+
* @author Oleg Zhurakousky
36+
*
37+
*/
38+
public class FunctionTypeProcessor implements BeanFactoryNativeConfigurationProcessor {
39+
40+
@Override
41+
public void process(ConfigurableListableBeanFactory beanFactory,
42+
NativeConfigurationRegistry registry) {
43+
new Processor().process(beanFactory, registry);
44+
}
45+
46+
private static class Processor {
47+
48+
void process(ConfigurableListableBeanFactory beanFactory, NativeConfigurationRegistry registry) {
49+
final Set<String> added = new HashSet<>();
50+
new BeanFactoryProcessor(beanFactory).processBeans(this::isFunction,
51+
(beanName, functionBeanType) -> {
52+
Type functionType = FunctionTypeUtils.discoverFunctionTypeFromClass(functionBeanType);
53+
Type inputType = FunctionTypeUtils.getInputType(functionType);
54+
String name = inputType.getTypeName();
55+
if (!name.startsWith("java.") &&
56+
!name.startsWith("javax.")) {
57+
if (added.add(name)) {
58+
registry.reflection().forType(FunctionTypeUtils.getRawType(inputType))
59+
.withAccess(TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.PUBLIC_CONSTRUCTORS, TypeAccess.DECLARED_FIELDS, TypeAccess.PUBLIC_FIELDS, TypeAccess.DECLARED_METHODS, TypeAccess.PUBLIC_METHODS);
60+
}
61+
}
62+
});
63+
}
64+
65+
private boolean isFunction(Class<?> beanType) {
66+
return Function.class.isAssignableFrom(beanType)
67+
|| Consumer.class.isAssignableFrom(beanType);
68+
// we don't care about Suppliers since it's output type is handled by the user code.
69+
}
70+
}
71+
72+
}

spring-aot/src/main/resources/META-INF/spring.factories

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ org.springframework.kafka.KafkaAvroNativeConfigurationProcessor,\
2929
org.springframework.validation.annotation.ValidatedNativeConfigurationProcessor,\
3030
org.springframework.web.WebNativeConfigurationProcessor,\
3131
org.springframework.core.SynthesizedAnnotationNativeConfigurationProcessor,\
32-
org.springframework.core.IndexedBeanHierarchyNativeConfigurationProcessor
32+
org.springframework.core.IndexedBeanHierarchyNativeConfigurationProcessor,\
33+
org.springframework.cloud.function.FunctionTypeProcessor
3334

3435
org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.BeanNativeConfigurationProcessor=\
3536
org.springframework.aot.context.bootstrap.generator.nativex.DefaultBeanNativeConfigurationProcessor,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2021-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.cloud.function;
18+
19+
import static org.assertj.core.api.Assertions.assertThat;
20+
21+
import java.util.Arrays;
22+
import java.util.HashSet;
23+
import java.util.List;
24+
import java.util.Set;
25+
import java.util.function.Consumer;
26+
import java.util.function.Function;
27+
import java.util.function.Supplier;
28+
29+
import org.junit.jupiter.api.Test;
30+
import org.springframework.aot.context.bootstrap.generator.infrastructure.nativex.NativeConfigurationRegistry;
31+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
32+
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
33+
import org.springframework.nativex.domain.reflect.ClassDescriptor;
34+
import org.springframework.nativex.hint.TypeAccess;
35+
36+
/**
37+
*
38+
* @author Oleg Zhurakousky
39+
*
40+
*/
41+
class FunctionTypeProcessorTests {
42+
43+
private static Set<TypeAccess> ALL_MEMBERS;
44+
{
45+
ALL_MEMBERS = new HashSet<>(Arrays.asList(TypeAccess.PUBLIC_FIELDS, TypeAccess.DECLARED_FIELDS, TypeAccess.DECLARED_CONSTRUCTORS, TypeAccess.PUBLIC_CONSTRUCTORS, TypeAccess.DECLARED_METHODS, TypeAccess.PUBLIC_METHODS));
46+
}
47+
48+
@Test
49+
void testFunctionTypes() {
50+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
51+
beanFactory.registerBeanDefinition("noise", BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition());
52+
beanFactory.registerBeanDefinition("sampleFunction", BeanDefinitionBuilder.rootBeanDefinition(MyFunction.class).getBeanDefinition());
53+
NativeConfigurationRegistry registry = process(beanFactory);
54+
List<ClassDescriptor> classDescriptors = registry.reflection().toClassDescriptors();
55+
assertThat(classDescriptors).hasSize(1);
56+
ClassDescriptor cd = classDescriptors.get(0);
57+
assertThat(cd.getName()).isEqualTo(Person.class.getName());
58+
assertThat(cd.getAccess()).containsAll(ALL_MEMBERS);
59+
}
60+
61+
@Test
62+
void testConsumerTypes() {
63+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
64+
beanFactory.registerBeanDefinition("noise", BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition());
65+
beanFactory.registerBeanDefinition("sampleConsumer", BeanDefinitionBuilder.rootBeanDefinition(MyConsumer.class).getBeanDefinition());
66+
NativeConfigurationRegistry registry = process(beanFactory);
67+
List<ClassDescriptor> classDescriptors = registry.reflection().toClassDescriptors();
68+
assertThat(classDescriptors).hasSize(1);
69+
ClassDescriptor cd = classDescriptors.get(0);
70+
assertThat(cd.getName()).isEqualTo(Person.class.getName());
71+
assertThat(cd.getAccess()).containsAll(ALL_MEMBERS);
72+
}
73+
74+
@Test
75+
void testSupplierTypes() {
76+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
77+
beanFactory.registerBeanDefinition("noise", BeanDefinitionBuilder.rootBeanDefinition(String.class).getBeanDefinition());
78+
beanFactory.registerBeanDefinition("sampleSupplier", BeanDefinitionBuilder.rootBeanDefinition(MySupplier.class).getBeanDefinition());
79+
NativeConfigurationRegistry registry = process(beanFactory);
80+
List<ClassDescriptor> classDescriptors = registry.reflection().toClassDescriptors();
81+
assertThat(classDescriptors).hasSize(0);
82+
}
83+
84+
private NativeConfigurationRegistry process(DefaultListableBeanFactory beanFactory) {
85+
NativeConfigurationRegistry registry = new NativeConfigurationRegistry();
86+
new FunctionTypeProcessor().process(beanFactory, registry);
87+
return registry;
88+
}
89+
90+
public static class MyFunction implements Function<Person, String> {
91+
@Override
92+
public String apply(Person t) {
93+
return null;
94+
}
95+
}
96+
97+
public static class MyConsumer implements Consumer<Person> {
98+
@Override
99+
public void accept(Person t) {
100+
}
101+
}
102+
103+
public static class MySupplier implements Supplier<Person> {
104+
@Override
105+
public Person get() {
106+
return null;
107+
}
108+
}
109+
110+
public static class Person {
111+
private String name;
112+
113+
public String getName() {
114+
return name;
115+
}
116+
117+
public void setName(String name) {
118+
this.name = name;
119+
}
120+
}
121+
}

0 commit comments

Comments
 (0)