Skip to content

Commit b4d37db

Browse files
committed
Add reproducer
See spring-projectsgh-32489
1 parent 88b9c05 commit b4d37db

File tree

1 file changed

+192
-0
lines changed

1 file changed

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

0 commit comments

Comments
 (0)