Skip to content

Commit 8fff5a2

Browse files
committed
Add BeanTypes registerTypes, for separate set of types that are excluded from isBeanAbsent()
These register types are not included in the isBeanAbsent() check
1 parent bacb492 commit 8fff5a2

File tree

12 files changed

+109
-14
lines changed

12 files changed

+109
-14
lines changed

blackbox-test-inject/src/main/java/org/example/myapp/beantypes/LimitedFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
import org.jspecify.annotations.Nullable;
88

99
import java.io.Serializable;
10+
import java.util.GregorianCalendar;
1011
import java.util.Optional;
1112

1213
@Factory
1314
public class LimitedFactory {
1415

1516
@Bean
1617
@Named("factory")
17-
@BeanTypes(LimitedInterface.class)
18+
@BeanTypes(value = LimitedInterface.class, registerTypes = GregorianCalendar.class)
1819
BeanTypeComponent bean() {
1920
return new BeanTypeComponent();
2021
}

blackbox-test-inject/src/main/java/org/example/myapp/lazy/generic/LazyGenericImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.example.myapp.lazy.generic;
22

3+
import java.util.Calendar;
34
import java.util.concurrent.atomic.AtomicBoolean;
45

56
import io.avaje.inject.BeanScope;
@@ -13,7 +14,7 @@
1314
@Lazy
1415
@Singleton
1516
@Named("single")
16-
@BeanTypes(LazyGenericInterface.class)
17+
@BeanTypes(value = LazyGenericInterface.class, registerTypes = Calendar.class)
1718
public class LazyGenericImpl implements LazyGenericInterface<String> {
1819

1920
AtomicBoolean initialized;

blackbox-test-inject/src/test/java/org/example/myapp/beantypes/BeanTypeComponentTest.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
import static org.assertj.core.api.Assertions.assertThat;
44
import static org.junit.jupiter.api.Assertions.assertFalse;
55

6+
import org.example.myapp.lazy.generic.LazyGenericImpl;
67
import org.junit.jupiter.api.Test;
78

89
import io.avaje.inject.BeanScope;
910

11+
import java.util.Calendar;
12+
import java.util.GregorianCalendar;
13+
1014
class BeanTypesTest {
1115

1216
@Test
@@ -17,6 +21,14 @@ void testBeanTypesRestrictingInjection() {
1721
assertThat(scope.get(AbstractSuperClass.class)).isNotNull();
1822
assertThat(scope.get(LimitedInterface.class)).isNotNull();
1923
assertThat(scope.get(CharSequence.class)).isEqualTo("IAmNullable");
24+
25+
Object extraTypeGregorianCalendar = scope.get(Calendar.class);
26+
assertThat(extraTypeGregorianCalendar).isNotNull();
27+
assertThat(extraTypeGregorianCalendar).isInstanceOf(LazyGenericImpl.class);
28+
29+
Object extraTypeCalendar = scope.get(GregorianCalendar.class);
30+
assertThat(extraTypeCalendar).isNotNull();
31+
assertThat(extraTypeCalendar).isInstanceOf(BeanTypeComponent.class);
2032
}
2133
}
2234
}

inject-generator/src/main/java/io/avaje/inject/generator/AssistBeanReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ final class AssistBeanReader {
3939
this.beanType = beanType;
4040
this.type = beanType.getQualifiedName().toString();
4141
this.typeReader =
42-
new TypeReader(List.of(), UType.parse(beanType.asType()), beanType, importTypes, false);
42+
new TypeReader(List.of(), List.of(), UType.parse(beanType.asType()), beanType, importTypes, false);
4343

4444
typeReader.process();
4545
qualifierName = typeReader.name();

inject-generator/src/main/java/io/avaje/inject/generator/BeanReader.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,22 @@ final class BeanReader {
7171
this.primary = PrimaryPrism.isPresent(actualType);
7272
this.secondary = !primary && SecondaryPrism.isPresent(actualType);
7373
this.priority = Util.priority(actualType);
74+
7475
var beanTypes =
7576
BeanTypesPrism.getOptionalOn(actualType)
7677
.map(BeanTypesPrism::value)
7778
.or(() -> proxy ? Optional.of(List.of(actualType.asType())) : Optional.empty());
7879
beanTypes.ifPresent(t -> Util.validateBeanTypes(actualType, t));
80+
81+
var extraTypes =
82+
BeanTypesPrism.getOptionalOn(actualType)
83+
.map(BeanTypesPrism::registerTypes)
84+
.orElse(List.of());
85+
7986
this.typeReader =
8087
new TypeReader(
8188
beanTypes.orElse(List.of()),
89+
extraTypes,
8290
UType.parse(beanType.asType()),
8391
beanType,
8492
importTypes,
@@ -149,7 +157,12 @@ private boolean shouldDelay() {
149157
.stream()
150158
.flatMap(List::stream);
151159

152-
return Stream.of(constructors, fields, methods, interfaces, superClass, beanTypes)
160+
var beanRegisterTypes = BeanTypesPrism.getOptionalOn(beanType)
161+
.map(BeanTypesPrism::registerTypes)
162+
.stream()
163+
.flatMap(List::stream);
164+
165+
return Stream.of(constructors, fields, methods, interfaces, superClass, beanTypes, beanRegisterTypes)
153166
.flatMap(s -> s)
154167
.map(TypeMirror::getKind)
155168
.anyMatch(TypeKind.ERROR::equals);
@@ -356,6 +369,10 @@ void buildBeanAbsent(Append writer) {
356369
}
357370
writer.append(typeReader.typesRegister());
358371
writer.append(")) {").eol();
372+
String extraTypesRegister = typeReader.extraTypesRegister();
373+
if (extraTypesRegister != null) {
374+
writer.append(" builder.registerTypes(%s);", extraTypesRegister).eol();
375+
}
359376
}
360377

361378
void buildRegister(Append writer) {

inject-generator/src/main/java/io/avaje/inject/generator/MethodReader.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,9 +141,14 @@ final class MethodReader {
141141
} else {
142142
var beanTypes = BeanTypesPrism.getOptionalOn(element).map(BeanTypesPrism::value);
143143
beanTypes.ifPresent(t -> Util.validateBeanTypes(element, t));
144+
145+
var extraTypes = BeanTypesPrism.getOptionalOn(element)
146+
.map(BeanTypesPrism::registerTypes)
147+
.orElse(List.of());
148+
144149
this.typeReader =
145150
new TypeReader(
146-
beanTypes.orElse(List.of()), genericType, returnElement, importTypes, element);
151+
beanTypes.orElse(List.of()), extraTypes, genericType, returnElement, importTypes, element);
147152
typeReader.process();
148153
MethodLifecycleReader lifecycleReader = new MethodLifecycleReader(returnElement, initMethod, destroyMethod);
149154
this.initMethod = lifecycleReader.initMethod();
@@ -475,6 +480,12 @@ void buildAddFor(Append writer) {
475480
}
476481
}
477482
writer.append(")) {").eol();
483+
if (typeReader != null) {
484+
String extraTypesRegister = typeReader.extraTypesRegister();
485+
if (extraTypesRegister != null) {
486+
writer.append(" builder.registerTypes(%s);", extraTypesRegister).eol();
487+
}
488+
}
478489
}
479490

480491
boolean methodThrows() {

inject-generator/src/main/java/io/avaje/inject/generator/TypeAppender.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ private static Stream<UType> allComponentTypes(UType u) {
4646
Stream.of(u), componentTypes.stream().flatMap(TypeAppender::allComponentTypes));
4747
}
4848

49-
void add(List<UType> sourceTypes) {
49+
TypeAppender add(List<UType> sourceTypes) {
5050
sourceTypes.forEach(this::add);
51+
return this;
5152
}
5253

5354
void addSimpleType(String classType) {

inject-generator/src/main/java/io/avaje/inject/generator/TypeReader.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,35 +21,41 @@ final class TypeReader {
2121
private final TypeAnnotationReader annotationReader;
2222
private Set<UType> genericTypes;
2323
private String typesRegister;
24+
private String extraTypesRegister;
2425
private final List<UType> injectsTypes;
26+
private final List<UType> extraTypes;
2527

2628
TypeReader(
2729
List<TypeMirror> injectsTypes,
30+
List<TypeMirror> extraTypes,
2831
UType genericType,
2932
TypeElement beanType,
3033
ImportTypeMap importTypes,
3134
boolean factory) {
32-
this(injectsTypes, genericType, true, beanType, importTypes, factory, beanType);
35+
this(injectsTypes, extraTypes, genericType, true, beanType, importTypes, factory, beanType);
3336
}
3437

3538
TypeReader(
3639
List<TypeMirror> injectsTypes,
40+
List<TypeMirror> extraTypes,
3741
UType genericType,
3842
TypeElement returnElement,
3943
ImportTypeMap importTypes,
4044
ExecutableElement source) {
41-
this(injectsTypes, genericType, false, returnElement, importTypes, false, source);
45+
this(injectsTypes, extraTypes, genericType, false, returnElement, importTypes, false, source);
4246
}
4347

4448
private TypeReader(
4549
List<TypeMirror> injectsTypes,
50+
List<TypeMirror> extraTypes,
4651
UType genericType,
4752
boolean forBean,
4853
TypeElement beanType,
4954
ImportTypeMap importTypes,
5055
boolean factory,
5156
Element source) {
5257
this.injectsTypes = injectsTypes.stream().map(UType::parse).collect(toList());
58+
this.extraTypes = extraTypes.stream().map(UType::parse).collect(toList());
5359
this.forBean = forBean;
5460
this.beanType = beanType;
5561
this.importTypes = importTypes;
@@ -63,6 +69,10 @@ String typesRegister() {
6369
return typesRegister;
6470
}
6571

72+
String extraTypesRegister() {
73+
return extraTypesRegister;
74+
}
75+
6676
List<String> provides() {
6777
var provides = providedTypes();
6878
provides.addAll(autoProvides());
@@ -156,6 +166,12 @@ private void initRegistrationTypes() {
156166
appender.add(extendsReader.provides());
157167
} else {
158168
appender.add(injectsTypes);
169+
if (!extraTypes.isEmpty()) {
170+
this.extraTypesRegister =
171+
new TypeAppender(importTypes)
172+
.add(extraTypes)
173+
.asString();
174+
}
159175
}
160176
this.genericTypes = appender.genericTypes();
161177
this.typesRegister = appender.asString();

inject/src/main/java/io/avaje/inject/BeanTypes.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,14 @@
77
@Target({ElementType.METHOD, ElementType.TYPE})
88
public @interface BeanTypes {
99

10+
/** The types the component will register to. */
1011
Class<?>[] value();
12+
13+
/**
14+
* Extra types to register the component to that are not included in the
15+
* <code>isBeanAbsent()</code> check. For testing purposes, when providing
16+
* test doubles, these types are not checked.
17+
*/
18+
Class<?>[] registerTypes() default {};
19+
1120
}

inject/src/main/java/io/avaje/inject/spi/Builder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ default boolean isBeanAbsent(Type... types) {
5757
return isBeanAbsent(null, types);
5858
}
5959

60+
/**
61+
* Register extra types that the next registered bean implements and provides.
62+
*/
63+
void registerTypes(Type... types);
64+
6065
/**
6166
* Register the next bean as having Primary priority.
6267
* Highest priority, wired over any other matching beans.

0 commit comments

Comments
 (0)