Skip to content

Commit 7703e94

Browse files
committed
Review, refactor and polish Spring Data AOT infrastructure classes.
* Refactored logic in AOT infrastructure classes. * Annotated AOT API with Spring's @nonnull and @nullable annotations. * Edited Javadoc. * Introduced PredicateUtils abstract utility class encapsulating common Predicates on types and class members. * Added comments for review and clarification.
1 parent 1084d30 commit 7703e94

11 files changed

+482
-164
lines changed

src/main/java/org/springframework/data/ManagedTypes.java

+68-15
Original file line numberDiff line numberDiff line change
@@ -22,43 +22,96 @@
2222
import java.util.stream.Stream;
2323

2424
import org.springframework.data.util.Lazy;
25+
import org.springframework.lang.NonNull;
2526

2627
/**
2728
* Types managed by a Spring Data implementation. Used to predefine a set of know entities that might need processing
28-
* during container/repository initialization phase.
29+
* during the Spring container, Spring Data Repository initialization phase.
2930
*
3031
* @author Christoph Strobl
32+
* @see java.lang.FunctionalInterface
3133
* @since 3.0
3234
*/
35+
@FunctionalInterface
3336
public interface ManagedTypes {
3437

35-
void forEach(Consumer<Class<?>> action);
36-
37-
default List<Class<?>> toList() {
38-
39-
List<Class<?>> tmp = new ArrayList<>(100);
40-
forEach(tmp::add);
41-
return tmp;
42-
}
43-
44-
static ManagedTypes of(Iterable<? extends Class<?>> types) {
38+
/**
39+
* Factory method used to construct {@link ManagedTypes} from the given {@link Iterable} of {@link Class types}.
40+
*
41+
* @param types {@link Iterable} of {@link Class types} used to initialize the new {@link ManagedTypes} instance;
42+
* must not be {@literal null}.
43+
* @return new instance of {@link ManagedTypes} initialized the given {@link Iterable} of {@link Class types}.
44+
* @see java.lang.Iterable
45+
* @see #of(Stream)
46+
* @see #of(Supplier)
47+
*/
48+
@NonNull
49+
static ManagedTypes of(@NonNull Iterable<? extends Class<?>> types) {
4550
return types::forEach;
4651
}
4752

48-
static ManagedTypes of(Stream<? extends Class<?>> types) {
53+
/**
54+
* Factory method used to construct {@link ManagedTypes} from the given {@link Stream} of {@link Class types}.
55+
*
56+
* @param types {@link Stream} of {@link Class types} used to initialize the new {@link ManagedTypes} instance;
57+
* must not be {@literal null}.
58+
* @return new instance of {@link ManagedTypes} initialized the given {@link Stream} of {@link Class types}.
59+
* @see java.util.stream.Stream
60+
* @see #of(Iterable)
61+
* @see #of(Supplier)
62+
*/
63+
@NonNull
64+
static ManagedTypes of(@NonNull Stream<? extends Class<?>> types) {
4965
return types::forEach;
5066
}
5167

52-
static ManagedTypes o(Supplier<Iterable<? extends Class<?>>> dataProvider) {
68+
/**
69+
* Factory method used to construct {@link ManagedTypes} from the given {@link Supplier} of
70+
* an {@link Iterable} of {@link Class types}.
71+
*
72+
* @param dataProvider {@link Supplier} of an {@link Iterable} of {@link Class types} used to lazily initialize
73+
* the new {@link ManagedTypes} instance; must not be {@literal null}.
74+
* @return new instance of {@link ManagedTypes} initialized the given {@link Supplier} of
75+
* an {@link Iterable} of {@link Class types}.
76+
* @see java.util.function.Supplier
77+
* @see java.lang.Iterable
78+
* @see #of(Iterable)
79+
* @see #of(Stream)
80+
*/
81+
@NonNull
82+
static ManagedTypes of(@NonNull Supplier<Iterable<? extends Class<?>>> dataProvider) {
5383

5484
return new ManagedTypes() {
5585

56-
Lazy<Iterable<? extends Class<?>>> lazyProvider = Lazy.of(dataProvider);
86+
final Lazy<Iterable<? extends Class<?>>> lazyProvider = Lazy.of(dataProvider);
5787

5888
@Override
59-
public void forEach(Consumer<Class<?>> action) {
89+
public void forEach(@NonNull Consumer<Class<?>> action) {
6090
lazyProvider.get().forEach(action);
6191
}
6292
};
6393
}
94+
95+
/**
96+
* Applies the given {@link Consumer action} to each of the {@link Class type} contained in
97+
* this {@link ManagedTypes} instance.
98+
*
99+
* @param action {@link Consumer} defining the action to perform on the {@link Class types}
100+
* contained in this {@link ManagedTypes} instance; must not be {@literal null}.
101+
* @see java.util.function.Consumer
102+
*/
103+
void forEach(Consumer<Class<?>> action);
104+
105+
/**
106+
* Returns all the {@link ManagedTypes} in a {@link List}.
107+
*
108+
* @return these {@link ManagedTypes} in a {@link List}; never {@literal null}.
109+
* @see java.util.List
110+
*/
111+
default List<Class<?>> toList() {
112+
113+
List<Class<?>> list = new ArrayList<>(100);
114+
forEach(list::add);
115+
return list;
116+
}
64117
}

src/main/java/org/springframework/data/aot/AotContext.java

+170-34
Original file line numberDiff line numberDiff line change
@@ -28,113 +28,249 @@
2828
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
2929
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
3030
import org.springframework.beans.factory.support.RootBeanDefinition;
31+
import org.springframework.lang.NonNull;
3132
import org.springframework.lang.Nullable;
3233
import org.springframework.util.Assert;
3334
import org.springframework.util.ClassUtils;
3435
import org.springframework.util.ObjectUtils;
3536

3637
/**
37-
* The context in which the AOT processing happens. Grants access to the {@link ConfigurableListableBeanFactory
38-
* beanFactory} and {@link ClassLoader}. Holds a few convenience methods to check if a type
39-
* {@link #isTypePresent(String) is present} and allows resolution of them. <strong>WARNING:</strong> Unstable internal
40-
* API!
38+
* The context in which the AOT processing happens.
39+
*
40+
* Grants access to the {@link ConfigurableListableBeanFactory beanFactory} and {@link ClassLoader}. Holds a few
41+
* convenience methods to check if a type {@link #isTypePresent(String) is present} and allows resolution of them.
42+
*
43+
* <strong>WARNING:</strong> Unstable internal API!
4144
*
4245
* @author Christoph Strobl
46+
* @author John Blum
47+
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory
48+
* @since 3.0
4349
*/
4450
public interface AotContext {
4551

4652
/**
4753
* Create an {@link AotContext} backed by the given {@link BeanFactory}.
4854
*
49-
* @param beanFactory must not be {@literal null}.
50-
* @return new instance of {@link AotContext}.
55+
* @param beanFactory reference to the {@link BeanFactory}; must not be {@literal null}.
56+
* @return a new instance of {@link AotContext}.
57+
* @see BeanFactory
5158
*/
52-
static AotContext context(BeanFactory beanFactory) {
59+
static AotContext from(@NonNull BeanFactory beanFactory) {
5360

54-
Assert.notNull(beanFactory, "BeanFactory must not be null!");
61+
Assert.notNull(beanFactory, "BeanFactory must not be null");
5562

5663
return new AotContext() {
5764

5865
private final ConfigurableListableBeanFactory bf = beanFactory instanceof ConfigurableListableBeanFactory
5966
? (ConfigurableListableBeanFactory) beanFactory
6067
: new DefaultListableBeanFactory(beanFactory);
6168

69+
@NonNull
6270
@Override
6371
public ConfigurableListableBeanFactory getBeanFactory() {
6472
return bf;
6573
}
6674
};
6775
}
6876

77+
/**
78+
* Returns a reference to the {@link ConfigurableListableBeanFactory} backing this {@link AotContext}.
79+
*
80+
* @return a reference to the {@link ConfigurableListableBeanFactory} backing this {@link AotContext}.
81+
* @see ConfigurableListableBeanFactory
82+
*/
6983
ConfigurableListableBeanFactory getBeanFactory();
7084

85+
/**
86+
* Returns the {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}.
87+
*
88+
* By default, this is the same {@link ClassLoader} used by the {@link BeanFactory} to resolve {@link Class types}
89+
* declared in bean definitions.
90+
*
91+
* @return the {@link ClassLoader} used by this {@link AotContext} to resolve {@link Class types}.
92+
* @see ConfigurableListableBeanFactory#getBeanClassLoader()
93+
*/
94+
@Nullable
7195
default ClassLoader getClassLoader() {
7296
return getBeanFactory().getBeanClassLoader();
7397
}
7498

75-
default boolean isTypePresent(String typeName) {
76-
return ClassUtils.isPresent(typeName, getBeanFactory().getBeanClassLoader());
99+
/**
100+
* Determines whether the given {@link String named} {@link Class type} is present on the application classpath.
101+
*
102+
* @param typeName {@link String name} of the {@link Class type} to evaluate; must not be {@literal null}.
103+
* @return {@literal true} if the given {@link String named} {@link Class type} is present
104+
* on the application classpath.
105+
* @see #getClassLoader()
106+
*/
107+
default boolean isTypePresent(@NonNull String typeName) {
108+
return ClassUtils.isPresent(typeName, getClassLoader());
77109
}
78110

111+
/**
112+
* Returns a new {@link TypeScanner} used to scan for {@link Class types} that will be contributed to the AOT
113+
* processing infrastructure.
114+
*
115+
* @return a {@link TypeScanner} used to scan for {@link Class types} that will be contributed to the AOT
116+
* processing infrastructure.
117+
* @see TypeScanner
118+
*/
119+
@NonNull
79120
default TypeScanner getTypeScanner() {
80121
return new TypeScanner(getClassLoader());
81122
}
82123

83-
default Set<Class<?>> scanPackageForTypes(Collection<Class<? extends Annotation>> identifyingAnnotations,
124+
/**
125+
* Scans for {@link Class types} in the given {@link String named packages} annotated with the store-specific
126+
* {@link Annotation identifying annotations}.
127+
*
128+
* @param identifyingAnnotations {@link Collection} of {@link Annotation Annotations} identifying store-specific
129+
* model {@link Class types}; must not be {@literal null}.
130+
* @param packageNames {@link Collection} of {@link String package names} to scan.
131+
* @return a {@link Set} of {@link Class types} found during the scan.
132+
* @see TypeScanner#scanForTypesAnnotatedWith(Class[])
133+
* @see TypeScanner.Scanner#inPackages(Collection)
134+
* @see #getTypeScanner()
135+
*/
136+
default Set<Class<?>> scanPackageForTypes(@NonNull Collection<Class<? extends Annotation>> identifyingAnnotations,
84137
Collection<String> packageNames) {
138+
85139
return getTypeScanner().scanForTypesAnnotatedWith(identifyingAnnotations).inPackages(packageNames);
86140
}
87141

88-
default Optional<Class<?>> resolveType(String typeName) {
89-
90-
if (!isTypePresent(typeName)) {
91-
return Optional.empty();
92-
}
93-
return Optional.of(resolveRequiredType(typeName));
94-
}
142+
/**
143+
* Resolves the required {@link String named} {@link Class type}.
144+
*
145+
* @param typeName {@link String} containing the {@literal fully-qualified class name} of the {@link Class type}
146+
* to resolve; must not be {@literal null}.
147+
* @return a resolved {@link Class type} for the given, required {@link String name}.
148+
* @throws TypeNotPresentException if the {@link String named} {@link Class type} cannot be found.
149+
*/
150+
@NonNull
151+
default Class<?> resolveRequiredType(@NonNull String typeName) throws TypeNotPresentException {
95152

96-
default Class<?> resolveRequiredType(String typeName) throws TypeNotPresentException {
97153
try {
98154
return ClassUtils.forName(typeName, getClassLoader());
99-
} catch (ClassNotFoundException e) {
100-
throw new TypeNotPresentException(typeName, e);
155+
} catch (ClassNotFoundException cause) {
156+
throw new TypeNotPresentException(typeName, cause);
101157
}
102158
}
103159

160+
/**
161+
* Resolves the given {@link String named} {@link Class type} if present.
162+
*
163+
* @param typeName {@link String} containing the {@literal fully-qualified class name} of the {@link Class type}
164+
* to resolve; must not be {@literal null}.
165+
* @return an {@link Optional} value containing the {@link Class type}
166+
* if the {@link String fully-qualified class name} is present on the application classpath.
167+
* @see #isTypePresent(String)
168+
* @see #resolveRequiredType(String)
169+
* @see java.util.Optional
170+
*/
171+
default Optional<Class<?>> resolveType(@NonNull String typeName) {
172+
173+
return isTypePresent(typeName)
174+
? Optional.of(resolveRequiredType(typeName))
175+
: Optional.empty();
176+
}
177+
178+
/**
179+
* Resolves the {@link BeanDefinition bean's} defined {@link Class type}.
180+
*
181+
* @param beanReference {@link BeanReference} to the managed bean.
182+
* @return the {@link Class type} of the {@link BeanReference referenced bean} if defined; may be {@literal null}.
183+
* @see BeanReference
184+
*/
104185
@Nullable
105-
default Class<?> resolveType(BeanReference beanReference) {
186+
default Class<?> resolveType(@NonNull BeanReference beanReference) {
106187
return getBeanFactory().getType(beanReference.getBeanName(), false);
107188
}
108189

109-
default BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
190+
/**
191+
* Gets the {@link BeanDefinition} for the given, required {@link String named bean}.
192+
*
193+
* @param beanName {@link String} containing the {@literal name} of the bean; must not be {@literal null}.
194+
* @return the {@link BeanDefinition} for the given, required {@link String named bean}.
195+
* @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} cannot be found for
196+
* the {@link String named bean}.
197+
* @see BeanDefinition
198+
*/
199+
@NonNull
200+
default BeanDefinition getBeanDefinition(@NonNull String beanName) throws NoSuchBeanDefinitionException {
110201
return getBeanFactory().getBeanDefinition(beanName);
111202
}
112203

113-
default RootBeanDefinition getRootBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {
204+
/**
205+
* Gets the {@link RootBeanDefinition} for the given, required {@link String bean name}.
206+
*
207+
* @param beanName {@link String} containing the {@literal name} of the bean.
208+
* @return the {@link RootBeanDefinition} for the given, required {@link String bean name}.
209+
* @throws NoSuchBeanDefinitionException if a {@link BeanDefinition} cannot be found for
210+
* the {@link String named bean}.
211+
* @throws IllegalStateException if the bean is not a {@link RootBeanDefinition root bean}.
212+
* @see RootBeanDefinition
213+
*/
214+
@NonNull
215+
default RootBeanDefinition getRootBeanDefinition(@NonNull String beanName) throws NoSuchBeanDefinitionException {
216+
217+
BeanDefinition beanDefinition = getBeanDefinition(beanName);
114218

115-
BeanDefinition val = getBeanFactory().getBeanDefinition(beanName);
116-
if (!(val instanceof RootBeanDefinition)) {
117-
throw new IllegalStateException(String.format("%s is not a root bean", beanName));
219+
if (beanDefinition instanceof RootBeanDefinition rootBeanDefinition) {
220+
return rootBeanDefinition;
118221
}
119-
return RootBeanDefinition.class.cast(val);
222+
223+
throw new IllegalStateException(String.format("%s is not a root bean", beanName));
120224
}
121225

122-
default boolean isFactoryBean(String beanName) {
226+
/**
227+
* Determines whether a bean identified by the given, required {@link String name} is a
228+
* {@link org.springframework.beans.factory.FactoryBean}.
229+
*
230+
* @param beanName {@link String} containing the {@literal name} of the bean to evaluate;
231+
* must not be {@literal null}.
232+
* @return {@literal true} if the bean identified by the given, required {@link String name} is a
233+
* {@link org.springframework.beans.factory.FactoryBean}.
234+
*/
235+
default boolean isFactoryBean(@NonNull String beanName) {
123236
return getBeanFactory().isFactoryBean(beanName);
124237
}
125238

239+
/**
240+
* Determines whether a Spring {@link org.springframework.transaction.TransactionManager} is present.
241+
*
242+
* @return {@literal true} if a Spring {@link org.springframework.transaction.TransactionManager} is present.
243+
*/
126244
default boolean isTransactionManagerPresent() {
127245

128-
return resolveType("org.springframework.transaction.TransactionManager") //
129-
.map(it -> !ObjectUtils.isEmpty(getBeanFactory().getBeanNamesForType(it))) //
130-
.orElse(false);
246+
return resolveType("org.springframework.transaction.TransactionManager")
247+
.filter(it -> !ObjectUtils.isEmpty(getBeanFactory().getBeanNamesForType(it)))
248+
.isPresent();
131249
}
132250

133-
default void ifTypePresent(String typeName, Consumer<Class<?>> action) {
251+
/**
252+
* Determines whether the given, required {@link String type name} is declared on the application classpath
253+
* and performs the given, required {@link Consumer action} if present.
254+
*
255+
* @param typeName {@link String name} of the {@link Class type} to process; must not be {@literal null}.
256+
* @param action {@link Consumer} defining the action to perform on the resolved {@link Class type};
257+
* must not be {@literal null}.
258+
* @see java.util.function.Consumer
259+
* @see #resolveType(String)
260+
*/
261+
default void ifTypePresent(@NonNull String typeName, @NonNull Consumer<Class<?>> action) {
134262
resolveType(typeName).ifPresent(action);
135263
}
136264

137-
default void ifTransactionManagerPresent(Consumer<String[]> beanNamesConsumer) {
265+
/**
266+
* Runs the given {@link Consumer action} on any {@link org.springframework.transaction.TransactionManager} beans
267+
* defined in the application context.
268+
*
269+
* @param beanNamesConsumer {@link Consumer} defining the action to perform on
270+
* the {@link org.springframework.transaction.TransactionManager} beans if present; must not be {@literal null}.
271+
* @see java.util.function.Consumer
272+
*/
273+
default void ifTransactionManagerPresent(@NonNull Consumer<String[]> beanNamesConsumer) {
138274

139275
ifTypePresent("org.springframework.transaction.TransactionManager", txMgrType -> {
140276
String[] txMgrBeanNames = getBeanFactory().getBeanNamesForType(txMgrType);

0 commit comments

Comments
 (0)