1+ /*
2+ * Copyright 2025-2025 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+ package org .springframework .ai .mcp .annotation .spring .scan ;
17+
18+ import org .junit .jupiter .api .Test ;
19+ import org .springframework .aot .generate .GenerationContext ;
20+ import org .springframework .aot .hint .RuntimeHints ;
21+ import org .springframework .aot .hint .TypeHint ;
22+ import org .springframework .aot .hint .TypeReference ;
23+ import org .springframework .beans .factory .aot .BeanFactoryInitializationAotContribution ;
24+ import org .springframework .beans .factory .aot .BeanFactoryInitializationCode ;
25+ import org .springframework .beans .factory .support .DefaultListableBeanFactory ;
26+ import org .springframework .beans .factory .support .RootBeanDefinition ;
27+
28+ import java .lang .annotation .*;
29+ import java .util .List ;
30+ import java .util .Set ;
31+
32+ import static org .assertj .core .api .Assertions .assertThat ;
33+ import static org .mockito .Mockito .mock ;
34+ import static org .mockito .Mockito .when ;
35+
36+ /**
37+ * Unit Tests for {@link AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor}.
38+ *
39+ * @author lance
40+ */
41+ class AbstractAnnotatedMethodBeanFactoryInitializationAotProcessorTests {
42+
43+ @ Test
44+ void processAheadOfTime () {
45+ // register bean(AnnotatedBean,PlainBean)
46+ DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory ();
47+ beanFactory .registerBeanDefinition (AnnotatedBean .class .getName (), new RootBeanDefinition (AnnotatedBean .class ));
48+ beanFactory .registerBeanDefinition (PlainBean .class .getName (), new RootBeanDefinition (PlainBean .class ));
49+
50+ PlainBean plainBean = beanFactory .getBean (PlainBean .class );
51+ assertThat (plainBean ).isNotNull ();
52+
53+ // create AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor
54+ Set <Class <? extends Annotation >> annotations = Set .of (MyAnnotation .class );
55+ AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor processor = new AbstractAnnotatedMethodBeanFactoryInitializationAotProcessor (
56+ annotations );
57+
58+ // execute processAheadOfTime
59+ BeanFactoryInitializationAotContribution aotContribution = processor .processAheadOfTime (beanFactory );
60+ assertThat (aotContribution ).isNotNull ();
61+
62+ // execute Contribution
63+ GenerationContext generationContext = mock (GenerationContext .class );
64+ when (generationContext .getRuntimeHints ()).thenReturn (new RuntimeHints ());
65+
66+ BeanFactoryInitializationCode initializationCode = mock (BeanFactoryInitializationCode .class );
67+ aotContribution .applyTo (generationContext , initializationCode );
68+
69+ // valid hints bean exist?
70+ List <TypeHint > typeHints = generationContext .getRuntimeHints ().reflection ().typeHints ().toList ();
71+ assertThat (typeHints ).isNotNull ().hasSize (1 );
72+
73+ TypeReference type = typeHints .get (0 ).getType ();
74+ assertThat (type ).matches (t -> t .getName ().equals (AnnotatedBean .class .getName ()))
75+ .doesNotMatch (t -> t .getName ().equals (PlainBean .class .getName ()));
76+ }
77+
78+ @ Target (ElementType .METHOD )
79+ @ Retention (RetentionPolicy .RUNTIME )
80+ @interface MyAnnotation {
81+
82+ }
83+
84+ /**
85+ * test bean
86+ */
87+ static class AnnotatedBean {
88+
89+ @ MyAnnotation
90+ public void doSomething () {
91+ }
92+
93+ }
94+
95+ static class PlainBean {
96+
97+ public void nothing () {
98+ }
99+
100+ }
101+
102+ }
0 commit comments