Skip to content

Commit 114afc4

Browse files
authored
Maven plugin for Helidon Service Inject (helidon-io#9461)
Merged Core Registry and Inject registry: - Single module with minimal dependencies - New core module to be used everywhere - Replaces ServiceLoader Introduce Helidon Service Maven Plugin: - generates application binding class - generates main class - updated tests
1 parent 51d07df commit 114afc4

File tree

453 files changed

+14082
-10314
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

453 files changed

+14082
-10314
lines changed

all/pom.xml

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,16 +1133,8 @@
11331133
<artifactId>helidon-service-codegen</artifactId>
11341134
</dependency>
11351135
<dependency>
1136-
<groupId>io.helidon.service.inject</groupId>
1137-
<artifactId>helidon-service-inject-codegen</artifactId>
1138-
</dependency>
1139-
<dependency>
1140-
<groupId>io.helidon.service.inject</groupId>
1141-
<artifactId>helidon-service-inject-api</artifactId>
1142-
</dependency>
1143-
<dependency>
1144-
<groupId>io.helidon.service.inject</groupId>
1145-
<artifactId>helidon-service-inject</artifactId>
1136+
<groupId>io.helidon.service</groupId>
1137+
<artifactId>helidon-service-maven-plugin</artifactId>
11461138
</dependency>
11471139
<dependency>
11481140
<groupId>io.helidon.metadata</groupId>

applications/parent/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@
212212
</execution>
213213
</executions>
214214
</plugin>
215+
<plugin>
216+
<groupId>io.helidon.service</groupId>
217+
<artifactId>helidon-service-project</artifactId>
218+
<version>${helidon.version}</version>
219+
</plugin>
215220
</plugins>
216221
</pluginManagement>
217222
</build>

bom/pom.xml

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,18 +1502,8 @@
15021502
<version>${helidon.version}</version>
15031503
</dependency>
15041504
<dependency>
1505-
<groupId>io.helidon.service.inject</groupId>
1506-
<artifactId>helidon-service-inject-codegen</artifactId>
1507-
<version>${helidon.version}</version>
1508-
</dependency>
1509-
<dependency>
1510-
<groupId>io.helidon.service.inject</groupId>
1511-
<artifactId>helidon-service-inject-api</artifactId>
1512-
<version>${helidon.version}</version>
1513-
</dependency>
1514-
<dependency>
1515-
<groupId>io.helidon.service.inject</groupId>
1516-
<artifactId>helidon-service-inject</artifactId>
1505+
<groupId>io.helidon.service</groupId>
1506+
<artifactId>helidon-service-maven-plugin</artifactId>
15171507
<version>${helidon.version}</version>
15181508
</dependency>
15191509

builder/api/pom.xml

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@
3636
<groupId>io.helidon.common</groupId>
3737
<artifactId>helidon-common</artifactId>
3838
</dependency>
39-
<dependency>
40-
<groupId>io.helidon.common</groupId>
41-
<artifactId>helidon-common-config</artifactId>
42-
<optional>true</optional>
43-
</dependency>
4439
</dependencies>
4540

4641
</project>

builder/api/src/main/java/io/helidon/builder/api/Option.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ private Option() {
3131
}
3232

3333
/**
34-
* Mark a prototype option as one that can be read from {@link io.helidon.common.config.Config}.
34+
* Mark a prototype option as one that can be read from {@code io.helidon.common.config.Config}.
3535
*/
3636
@Target(ElementType.METHOD)
3737
@Inherited
@@ -152,6 +152,30 @@ private Option() {
152152
boolean discoverServices() default true;
153153
}
154154

155+
/**
156+
* Options annotated with this annotation will use service registry to discover instances to use.
157+
* This annotation cannot be combined with {@link io.helidon.builder.api.Option.Configured} - if you want
158+
* providers configured from configuration, kindly use {@link io.helidon.builder.api.Option.Provider}.
159+
* <p>
160+
* Behavior depends on the return type of the annotated method:
161+
* <ul>
162+
* <li>A single instance - if the instance is configured on the builder by hand, registry is not used</li>
163+
* <li>An {@link java.util.Optional} instance - ditto</li>
164+
* <li>A {@link java.util.List} of instances - instances configured on the builder are combined with instances
165+
* discovered in the registry; there is a generated method that allows for disabling registry use for each
166+
* service</li>
167+
* </ul>
168+
*
169+
* Options annotated with this annotation will load the instances as the default value (before method {@code builder()})
170+
* returns, thus you have full control over the field, be it an Optional, single value, or a List.
171+
* <p>
172+
* To support usage of custom service registry, a {@code builder(ServiceRegistry)} method will be generated as well.
173+
*/
174+
@Target(ElementType.METHOD)
175+
@Retention(RetentionPolicy.CLASS)
176+
public @interface RegistryService {
177+
}
178+
155179
/**
156180
* Allowed values for this option.
157181
* The allowed value is always configured as a string, and is compared to {@link java.lang.String#valueOf(Object)} of the

builder/api/src/main/java/io/helidon/builder/api/Prototype.java

Lines changed: 1 addition & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,6 @@
2121
import java.lang.annotation.Retention;
2222
import java.lang.annotation.RetentionPolicy;
2323
import java.lang.annotation.Target;
24-
import java.util.List;
25-
import java.util.Optional;
26-
27-
import io.helidon.common.HelidonServiceLoader;
28-
import io.helidon.common.config.Config;
29-
import io.helidon.common.config.ConfiguredProvider;
30-
import io.helidon.common.config.NamedService;
3124

3225
/**
3326
* Prototype is generated from a prototype blueprint, and it is expected to be part of the public API of the module.
@@ -72,102 +65,6 @@ default BUILDER self() {
7265
}
7366
}
7467

75-
/**
76-
* Extension of {@link io.helidon.builder.api.Prototype.Builder} that supports configuration.
77-
* If a blueprint is marked as {@code @Configured}, build will accept configuration.
78-
*
79-
* @param <BUILDER> type of the builder
80-
* @param <PROTOTYPE> type of the prototype to be built
81-
*/
82-
public interface ConfiguredBuilder<BUILDER, PROTOTYPE> extends Builder<BUILDER, PROTOTYPE> {
83-
/**
84-
* Update builder from configuration.
85-
* Any configured option that is defined on this prototype will be checked in configuration, and if it exists,
86-
* it will override current value for that option on this builder.
87-
* Options that do not exist in the provided config will not impact current values.
88-
* The config instance is kept and may be used in builder decorator, it is not available in prototype implementation.
89-
*
90-
* @param config configuration to use
91-
* @return updated builder instance
92-
*/
93-
BUILDER config(Config config);
94-
95-
/**
96-
* Discover services from configuration.
97-
* If already configured instances already contain a service of the same type and name that would be added from
98-
* configuration, the configuration would be ignored (e.g. the user must make a choice whether to configure, or
99-
* set using an API).
100-
*
101-
* @param config configuration located at the parent node of the service providers
102-
* @param configKey configuration key of the provider list
103-
* (either a list node, or object, where each child is one service)
104-
* @param serviceLoader helidon service loader for the expected type
105-
* @param providerType type of the service provider interface
106-
* @param configType type of the configured service
107-
* @param allFromServiceLoader whether all services from service loader should be used, or only the ones with configured
108-
* node
109-
* @param existingInstances already configured instances
110-
* @param <S> type of the expected service
111-
* @param <T> type of the configured service provider that creates instances of S
112-
* @return list of discovered services, ordered by {@link io.helidon.common.Weight} (highest weight is first in the list)
113-
*/
114-
default <S extends NamedService, T extends ConfiguredProvider<S>> List<S>
115-
discoverServices(Config config,
116-
String configKey,
117-
HelidonServiceLoader<T> serviceLoader,
118-
Class<T> providerType,
119-
Class<S> configType,
120-
boolean allFromServiceLoader,
121-
List<S> existingInstances) {
122-
return ProvidedUtil.discoverServices(config,
123-
configKey,
124-
serviceLoader,
125-
providerType,
126-
configType,
127-
allFromServiceLoader,
128-
existingInstances);
129-
}
130-
131-
/**
132-
* Discover service from configuration. If an instance is already configured using a builder, it will not be
133-
* discovered from configuration (e.g. the user must make a choice whether to configure, or set using API).
134-
*
135-
* @param config configuration located at the parent node of the service providers
136-
* @param configKey configuration key of the provider list
137-
* (either a list node, or object, where each child is one service - this method requires
138-
* * zero to one configured services)
139-
* @param serviceLoader helidon service loader for the expected type
140-
* @param providerType type of the service provider interface
141-
* @param configType type of the configured service
142-
* @param allFromServiceLoader whether all services from service loader should be used, or only the ones with configured
143-
* node
144-
* @param existingValue value already configured, if the name is same as discovered from configuration
145-
* @param <S> type of the expected service
146-
* @param <T> type of the configured service provider that creates instances of S
147-
* @return the first service (ordered by {@link io.helidon.common.Weight} that is discovered, or empty optional if none
148-
* is found
149-
*/
150-
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
151-
default <S extends NamedService, T extends ConfiguredProvider<S>> Optional<S>
152-
discoverService(Config config,
153-
String configKey,
154-
HelidonServiceLoader<T> serviceLoader,
155-
Class<T> providerType,
156-
Class<S> configType,
157-
boolean allFromServiceLoader,
158-
Optional<S> existingValue) {
159-
return ProvidedUtil.discoverService(config,
160-
configKey,
161-
serviceLoader,
162-
providerType,
163-
configType,
164-
allFromServiceLoader,
165-
existingValue);
166-
}
167-
168-
169-
}
170-
17168
/**
17269
* A prototype {@link Prototype.Blueprint} may extend this interface
17370
* to explicitly reference the associated runtime type.
@@ -262,7 +159,7 @@ public interface Factory<T> {
262159

263160
/**
264161
* A blueprint annotated with this annotation will create a prototype that can be created from a
265-
* {@link io.helidon.common.config.Config} instance. The builder will also have a method {@code config(Config)} that
162+
* {@code io.helidon.common.config.Config} instance. The builder will also have a method {@code config(Config)} that
266163
* reads all options annotated with {@link io.helidon.builder.api.Option.Configured} from the config.
267164
*/
268165
@Target(ElementType.TYPE)

builder/api/src/main/java/module-info.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022, 2023 Oracle and/or its affiliates.
2+
* Copyright (c) 2022, 2024 Oracle and/or its affiliates.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -21,8 +21,5 @@
2121

2222
requires transitive io.helidon.common;
2323

24-
requires static io.helidon.common.config;
25-
2624
exports io.helidon.builder.api;
27-
2825
}

builder/codegen/src/main/java/io/helidon/builder/codegen/AnnotationDataOption.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import static io.helidon.builder.codegen.Types.OPTION_DEFAULT_METHOD;
4646
import static io.helidon.builder.codegen.Types.OPTION_PROVIDER;
4747
import static io.helidon.builder.codegen.Types.OPTION_REDUNDANT;
48+
import static io.helidon.builder.codegen.Types.OPTION_REGISTRY_SERVICE;
4849
import static io.helidon.builder.codegen.Types.OPTION_REQUIRED;
4950
import static io.helidon.builder.codegen.Types.OPTION_SAME_GENERIC;
5051
import static io.helidon.builder.codegen.Types.OPTION_SINGULAR;
@@ -60,6 +61,7 @@ record AnnotationDataOption(Javadoc javadoc,
6061
AccessModifier accessModifier,
6162
boolean required,
6263
boolean validateNotNull,
64+
boolean registryService,
6365
boolean provider,
6466
TypeName providerType,
6567
boolean providerDiscoverServices,
@@ -101,6 +103,7 @@ static AnnotationDataOption create(TypeHandler handler, TypedElementInfo element
101103
.orElse(false);
102104
}
103105
accessModifier = accessModifier(element);
106+
boolean registryService = element.hasAnnotation(OPTION_REGISTRY_SERVICE);
104107
if (element.hasAnnotation(OPTION_PROVIDER)) {
105108
Annotation annotation = element.annotation(OPTION_PROVIDER);
106109
providerBased = true;
@@ -171,6 +174,7 @@ static AnnotationDataOption create(TypeHandler handler, TypedElementInfo element
171174
accessModifier,
172175
required,
173176
validateNotNull,
177+
registryService,
174178
providerBased,
175179
providerType,
176180
discoverServices,

builder/codegen/src/main/java/io/helidon/builder/codegen/BuilderCodegen.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ private static void addBuilderMethod(ClassModel.Builder classModel,
200200
TypeName builderTypeName,
201201
List<TypeArgument> typeArguments,
202202
String ifaceName) {
203+
203204
classModel.addMethod(builder -> {
204205
builder.isStatic(true)
205206
.name("builder")
@@ -438,7 +439,7 @@ private void process(RoundContext roundContext, TypeInfo blueprint) {
438439
blueprint.typeName(),
439440
blueprint.originatingElementValue());
440441

441-
if (typeContext.typeInfo().supportsServiceRegistry() && typeContext.propertyData().hasProvider()) {
442+
if (typeContext.typeInfo().supportsServiceRegistry()) {
442443
for (PrototypeProperty property : typeContext.propertyData().properties()) {
443444
if (property.configuredOption().provider()) {
444445
this.serviceLoaderContracts.add(property.configuredOption().providerType().genericTypeName().fqName());

builder/codegen/src/main/java/io/helidon/builder/codegen/CustomMethods.java

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.ArrayList;
2020
import java.util.List;
2121
import java.util.Optional;
22+
import java.util.Set;
2223
import java.util.function.Consumer;
2324
import java.util.function.Predicate;
2425
import java.util.stream.Collectors;
@@ -129,7 +130,8 @@ private static GeneratedMethod prototypeMethod(Errors.Collector errors,
129130
customMethod.returnType(),
130131
generatedArgs,
131132
// todo the javadoc may differ (such as when we have an additional parameter for instance methods)
132-
customMethod.javadoc()),
133+
customMethod.javadoc(),
134+
customMethod.typeParameters()),
133135
annotations,
134136
codeGenerator);
135137
}
@@ -178,7 +180,8 @@ private static GeneratedMethod builderMethod(Errors.Collector errors,
178180
customMethod.name(),
179181
typeInformation.prototypeBuilder(),
180182
generatedArgs,
181-
customMethod.javadoc()),
183+
customMethod.javadoc(),
184+
customMethod.typeParameters),
182185
annotations,
183186
codeGenerator);
184187
}
@@ -227,7 +230,8 @@ private static GeneratedMethod factoryMethod(Errors.Collector errors,
227230
customMethod.name(),
228231
customMethod.returnType(),
229232
customMethod.arguments(),
230-
customMethod.javadoc()),
233+
customMethod.javadoc(),
234+
customMethod.typeParameters()),
231235
annotations,
232236
codeGenerator);
233237
}
@@ -314,7 +318,26 @@ private static List<CustomMethod> findMethods(TypeContext.TypeInformation typeIn
314318
.filter(Predicate.not(String::isBlank)) // we do not care about blank values
315319
.toList();
316320

317-
Method customMethod = new Method(customMethodsType.typeName(), methodName, returnType, arguments, javadoc);
321+
List<TypeName> typeNames = it.typeParameters();
322+
List<TypeName> typeParametersToUse = new ArrayList<>();
323+
if (!typeNames.isEmpty()) {
324+
// look for type parameters that differ in name from the ones defined by the blueprint
325+
Set<String> usedNames = typeInformation.blueprintType().declaredType()
326+
.typeArguments()
327+
.stream()
328+
.map(TypeName::className)
329+
.collect(Collectors.toSet());
330+
typeNames.stream()
331+
.filter(methodTypeParam -> !usedNames.contains(methodTypeParam.className()))
332+
.forEach(typeParametersToUse::add);
333+
}
334+
335+
Method customMethod = new Method(customMethodsType.typeName(),
336+
methodName,
337+
returnType,
338+
arguments,
339+
javadoc,
340+
typeParametersToUse);
318341

319342
return new CustomMethod(customMethod,
320343
methodProcessor.process(errors,
@@ -343,7 +366,8 @@ record Method(TypeName declaringType,
343366
String name,
344367
TypeName returnType,
345368
List<Argument> arguments,
346-
List<String> javadoc) {
369+
List<String> javadoc,
370+
List<TypeName> typeParameters) {
347371

348372
}
349373

0 commit comments

Comments
 (0)