Skip to content

Commit 802967f

Browse files
committed
Add reproducer
See gh-32489
1 parent 2232890 commit 802967f

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
/*
2+
* Copyright 2002-2024 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.context.annotation;
18+
19+
import java.util.List;
20+
21+
import org.junit.jupiter.api.Disabled;
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.springframework.beans.BeanUtils;
25+
import org.springframework.beans.factory.FactoryBean;
26+
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.beans.factory.support.RootBeanDefinition;
28+
import org.springframework.core.ResolvableType;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* Tests for gh-32489
34+
*
35+
* @author Stephane Nicoll
36+
*/
37+
public class Gh32489Tests {
38+
39+
@Test
40+
void resolveFactoryBeansWithWildcard() {
41+
try (AnnotationConfigApplicationContext context = prepareContext()) {
42+
context.register(SimpleRepositoryFactoriesBeanHolder.class);
43+
context.refresh();
44+
assertThat(context.getBean(SimpleRepositoryFactoriesBeanHolder.class).repositoryFactoryies)
45+
.containsOnly(context.getBean("&repositoryFactoryBean", SimpleRepositoryFactoryBean.class));
46+
}
47+
}
48+
49+
@Test
50+
void resolveFactoryBeansParentInterfaceWithWildcard() {
51+
try (AnnotationConfigApplicationContext context = prepareContext()) {
52+
context.register(RepositoryFactoriesInformationHolder.class);
53+
context.refresh();
54+
assertThat(context.getBean(RepositoryFactoriesInformationHolder.class).repositoryFactoresInformation)
55+
.containsOnly(context.getBean("&repositoryFactoryBean", SimpleRepositoryFactoryBean.class));
56+
}
57+
}
58+
59+
@Test
60+
void resolveFactoryBeanWithMatchingGenerics() {
61+
try (AnnotationConfigApplicationContext context = prepareContext()) {
62+
context.register(RepositoryFactoryHolder.class);
63+
context.refresh();
64+
assertThat(context.getBean(RepositoryFactoryHolder.class).repositoryFactory)
65+
.isEqualTo(context.getBean("&repositoryFactoryBean"));
66+
}
67+
}
68+
69+
@Test
70+
@Disabled
71+
void resolveFactoryBeanWithMatchingGeneric() {
72+
try (AnnotationConfigApplicationContext context = prepareContext()) {
73+
context.refresh();
74+
ResolvableType requiredType = ResolvableType.forClassWithGenerics(SimpleRepositoryFactoryBean.class,
75+
EmployeeRepository.class, Long.class);
76+
assertThat(context.getBeanProvider(requiredType)).containsOnly(context.getBean("&repositoryFactoryBean"));
77+
}
78+
}
79+
80+
@Test
81+
void resolveFactoryBeanWithFirstNonMatchingGeneric() {
82+
try (AnnotationConfigApplicationContext context = prepareContext()) {
83+
context.refresh();
84+
ResolvableType requiredType = ResolvableType.forClassWithGenerics(SimpleRepositoryFactoryBean.class,
85+
TestBean.class, Long.class);
86+
assertThat(context.getBeanProvider(requiredType)).hasSize(0);
87+
}
88+
}
89+
90+
@Test
91+
void resolveFactoryBeanWithSecondNonMatchingGeneric() {
92+
try (AnnotationConfigApplicationContext context = prepareContext()) {
93+
context.refresh();
94+
ResolvableType requiredType = ResolvableType.forClassWithGenerics(SimpleRepositoryFactoryBean.class,
95+
EmployeeRepository.class, String.class);
96+
assertThat(context.getBeanProvider(requiredType)).hasSize(0);
97+
}
98+
}
99+
100+
@Test
101+
void resolveFactoryBeanTargetTypeWithMatchingGeneric() {
102+
try (AnnotationConfigApplicationContext context = prepareContext()) {
103+
context.refresh();
104+
ResolvableType requiredType = ResolvableType.forClassWithGenerics(Repository.class,
105+
Employee.class, Long.class);
106+
assertThat(context.getBeanProvider(requiredType)).
107+
containsOnly(context.getBean("repositoryFactoryBean"));
108+
}
109+
}
110+
111+
@Test
112+
void resolveFactoryBeanTargetTypeWithFirstNonMatchingGeneric() {
113+
try (AnnotationConfigApplicationContext context = prepareContext()) {
114+
context.refresh();
115+
ResolvableType requiredType = ResolvableType.forClassWithGenerics(Repository.class,
116+
TestBean.class, Long.class);
117+
assertThat(context.getBeanProvider(requiredType)).hasSize(0);
118+
}
119+
}
120+
121+
@Test
122+
void resolveFactoryBeanTargetTypeWithSecondNonMatchingGeneric() {
123+
try (AnnotationConfigApplicationContext context = prepareContext()) {
124+
context.refresh();
125+
ResolvableType requiredType = ResolvableType.forClassWithGenerics(Repository.class,
126+
Employee.class, String.class);
127+
assertThat(context.getBeanProvider(requiredType)).hasSize(0);
128+
}
129+
}
130+
131+
private AnnotationConfigApplicationContext prepareContext() {
132+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
133+
RootBeanDefinition rbd = new RootBeanDefinition(SimpleRepositoryFactoryBean.class);
134+
rbd.setTargetType(ResolvableType.forClassWithGenerics(SimpleRepositoryFactoryBean.class,
135+
EmployeeRepository.class, Long.class));
136+
rbd.getConstructorArgumentValues().addIndexedArgumentValue(0, EmployeeRepository.class);
137+
context.registerBeanDefinition("repositoryFactoryBean", rbd);
138+
return context;
139+
}
140+
141+
142+
static class SimpleRepositoryFactoriesBeanHolder {
143+
144+
@Autowired
145+
List<SimpleRepositoryFactoryBean<?, ?>> repositoryFactoryies;
146+
147+
}
148+
149+
static class RepositoryFactoriesInformationHolder {
150+
151+
@Autowired
152+
List<RepositoryFactoryInformation<?, ?>> repositoryFactoresInformation;
153+
154+
}
155+
156+
static class RepositoryFactoryHolder {
157+
158+
@Autowired
159+
SimpleRepositoryFactoryBean<EmployeeRepository, Long> repositoryFactory;
160+
161+
}
162+
163+
static class SimpleRepositoryFactoryBean<T, ID> extends RepositoryFactoryBeanSupport<T, ID> {
164+
165+
private final Class<? extends T> repositoryType;
166+
167+
public SimpleRepositoryFactoryBean(Class<? extends T> repositoryType) {
168+
this.repositoryType = repositoryType;
169+
}
170+
171+
@Override
172+
public T getObject() throws Exception {
173+
return BeanUtils.instantiateClass(this.repositoryType);
174+
}
175+
176+
@Override
177+
public Class<?> getObjectType() {
178+
return this.repositoryType;
179+
}
180+
}
181+
182+
abstract static class RepositoryFactoryBeanSupport<T, ID> implements FactoryBean<T>, RepositoryFactoryInformation<T, ID> {
183+
}
184+
185+
interface RepositoryFactoryInformation<T, ID> {
186+
}
187+
188+
interface Repository<T, ID> {}
189+
190+
static class EmployeeRepository implements Repository<Employee, Long> {}
191+
192+
record Employee(Long id, String name) {}
193+
194+
}

0 commit comments

Comments
 (0)